From 14d807232f3b37e706ec82c2f72a1cd96f131e47 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 12 Dec 2018 21:54:14 +0100 Subject: [PATCH] Finally remove legacy package and clean some files. --- .../internal/legacy/MXDataHandler.java | 2137 ------------ .../android/internal/legacy/MXPatterns.java | 138 - .../android/internal/legacy/MXSession.java | 2549 -------------- .../internal/legacy/MxEventDispatcher.java | 738 ----- .../android/internal/legacy/RestClient.java | 414 --- .../legacy/call/CallSoundsManager.java | 797 ----- .../call/HeadsetConnectionReceiver.java | 235 -- .../android/internal/legacy/call/IMXCall.java | 337 -- .../internal/legacy/call/IMXCallListener.java | 75 - .../legacy/call/IMXCallsManagerListener.java | 61 - .../android/internal/legacy/call/MXCall.java | 706 ---- .../internal/legacy/call/MXCallListener.java | 53 - .../internal/legacy/call/MXCallsManager.java | 1295 -------- .../legacy/call/MXCallsManagerListener.java | 46 - .../internal/legacy/call/MXChromeCall.java | 687 ---- .../internal/legacy/call/MXWebRtcCall.java | 1733 ---------- .../internal/legacy/call/MXWebRtcView.java | 520 --- .../legacy/call/VideoLayoutConfiguration.java | 90 - .../legacy/crypto/IncomingRoomKeyRequest.java | 76 - .../IncomingRoomKeyRequestCancellation.java | 30 - .../internal/legacy/crypto/MXCrypto.java | 2775 ---------------- .../legacy/crypto/MXCryptoAlgorithms.java | 136 - .../legacy/crypto/MXCryptoConfig.java | 26 - .../internal/legacy/crypto/MXCryptoError.java | 139 - .../legacy/crypto/MXDecryptionException.java | 62 - .../internal/legacy/crypto/MXDeviceList.java | 835 ----- .../legacy/crypto/MXEncryptedAttachments.java | 270 -- .../crypto/MXEventDecryptionResult.java | 52 - .../crypto/MXMegolmExportEncryption.java | 370 --- .../internal/legacy/crypto/MXOlmDevice.java | 830 ----- .../MXOutgoingRoomKeyRequestManager.java | 371 --- .../legacy/crypto/OutgoingRoomKeyRequest.java | 124 - .../crypto/algorithms/IMXDecrypting.java | 79 - .../crypto/algorithms/IMXEncrypting.java | 49 - .../crypto/algorithms/MXDecryptionResult.java | 48 - .../algorithms/megolm/MXMegolmDecryption.java | 468 --- .../algorithms/megolm/MXMegolmEncryption.java | 714 ---- .../megolm/MXOutboundSessionInfo.java | 89 - .../algorithms/olm/MXOlmDecryption.java | 272 -- .../algorithms/olm/MXOlmEncryption.java | 126 - .../legacy/crypto/data/MXDeviceInfo.java | 225 -- .../data/MXEncryptEventContentResult.java | 46 - .../internal/legacy/crypto/data/MXKey.java | 140 - .../crypto/data/MXOlmInboundGroupSession.java | 60 - .../data/MXOlmInboundGroupSession2.java | 172 - .../crypto/data/MXOlmSessionResult.java | 43 - .../crypto/data/MXQueuedEncryption.java | 35 - .../legacy/crypto/data/MXUsersDevicesMap.java | 186 -- .../internal/legacy/data/DataRetriever.java | 423 --- .../android/internal/legacy/data/MyUser.java | 446 --- .../android/internal/legacy/data/Pusher.java | 37 - .../android/internal/legacy/data/Room.java | 2939 ----------------- .../internal/legacy/data/RoomAccountData.java | 83 - .../legacy/data/RoomEmailInvitation.java | 49 - .../legacy/data/RoomMediaMessage.java | 901 ----- .../legacy/data/RoomMediaMessagesSender.java | 983 ------ .../internal/legacy/data/RoomPreviewData.java | 275 -- .../internal/legacy/data/RoomState.java | 1334 -------- .../internal/legacy/data/RoomSummary.java | 593 ---- .../android/internal/legacy/data/RoomTag.java | 92 - .../legacy/data/comparator/Comparators.java | 40 - .../comparator/RoomComparatorWithTag.java | 50 - .../data/cryptostore/IMXCryptoStore.java | 310 -- .../data/cryptostore/MXFileCryptoStore.java | 1743 ---------- .../MXFileCryptoStoreMetaData.java | 31 - .../MXFileCryptoStoreMetaData2.java | 75 - .../legacy/data/metrics/MetricsListener.java | 52 - .../internal/legacy/data/store/IMXStore.java | 645 ---- .../legacy/data/store/IMXStoreListener.java | 61 - .../legacy/data/store/MXFileStore.java | 2607 --------------- .../data/store/MXFileStoreMetaData.java | 91 - .../legacy/data/store/MXMemoryStore.java | 1666 ---------- .../legacy/data/store/MXStoreListener.java | 42 - .../legacy/data/timeline/EventTimeline.java | 235 -- .../data/timeline/EventTimelineFactory.java | 91 - .../legacy/data/timeline/MXEventTimeline.java | 990 ------ .../timeline/StateEventRedactionChecker.java | 175 - .../data/timeline/TimelineEventListeners.java | 105 - .../data/timeline/TimelineEventSaver.java | 74 - .../TimelineInvitedRoomSyncHandler.java | 68 - .../timeline/TimelineJoinRoomSyncHandler.java | 298 -- .../timeline/TimelineLiveEventHandler.java | 285 -- .../data/timeline/TimelinePushWorker.java | 91 - .../data/timeline/TimelineStateHolder.java | 149 - .../legacy/db/MXLatestChatMessageCache.java | 168 - .../legacy/db/MXMediaDownloadWorkerTask.java | 1158 ------- .../legacy/db/MXMediaUploadWorkerTask.java | 570 ---- .../internal/legacy/db/MXMediasCache.java | 1522 --------- .../internal/legacy/groups/GroupsManager.java | 802 ----- .../legacy/interfaces/DatedObject.java | 25 - .../legacy/interfaces/HtmlToolbox.java | 49 - .../legacy/listeners/IMXEventListener.java | 265 -- .../listeners/IMXMediaDownloadListener.java | 115 - .../listeners/IMXMediaUploadListener.java | 116 - .../listeners/IMXNetworkEventListener.java | 26 - .../legacy/listeners/MXEventListener.java | 166 - .../listeners/MXMediaDownloadListener.java | 45 - .../listeners/MXMediaUploadListener.java | 43 - .../legacy/listeners/MXRoomEventListener.java | 237 -- .../network/NetworkConnectivityReceiver.java | 317 -- .../legacy/rest/api/AccountDataApi.java | 48 - .../legacy/rest/api/CallRulesApi.java | 26 - .../internal/legacy/rest/api/CryptoApi.java | 112 - .../internal/legacy/rest/api/EventsApi.java | 101 - .../internal/legacy/rest/api/FilterApi.java | 48 - .../internal/legacy/rest/api/GroupsApi.java | 196 -- .../internal/legacy/rest/api/LoginApi.java | 70 - .../legacy/rest/api/MediaScanApi.java | 63 - .../internal/legacy/rest/api/PresenceApi.java | 35 - .../internal/legacy/rest/api/ProfileApi.java | 176 - .../legacy/rest/api/PushRulesApi.java | 78 - .../internal/legacy/rest/api/PushersApi.java | 36 - .../internal/legacy/rest/api/RoomsApi.java | 410 --- .../internal/legacy/rest/api/ThirdPidApi.java | 68 - .../legacy/rest/callback/ApiCallback.java | 26 - .../rest/callback/ApiFailureCallback.java | 45 - .../DefaultRetrofit2CallbackWrapper.java | 48 - .../DefaultRetrofit2ResponseHandler.java | 24 - .../rest/callback/RestAdapterCallback.java | 274 -- .../rest/callback/SimpleApiCallback.java | 139 - .../legacy/rest/callback/SuccessCallback.java | 26 - .../rest/callback/ToastErrorHandler.java | 60 - .../rest/client/AccountDataRestClient.java | 92 - .../legacy/rest/client/CallRestClient.java | 38 - .../legacy/rest/client/CryptoRestClient.java | 307 -- .../legacy/rest/client/EventsRestClient.java | 603 ---- .../legacy/rest/client/FilterRestClient.java | 73 - .../legacy/rest/client/GroupsRestClient.java | 434 --- .../legacy/rest/client/LoginRestClient.java | 359 -- .../rest/client/MXRestExecutorService.java | 76 - .../rest/client/MediaScanRestClient.java | 175 - .../rest/client/PresenceRestClient.java | 55 - .../legacy/rest/client/ProfileRestClient.java | 466 --- .../rest/client/PushRulesRestClient.java | 89 - .../legacy/rest/client/PushersRestClient.java | 166 - .../legacy/rest/client/RoomsRestClient.java | 1022 ------ .../rest/client/ThirdPidRestClient.java | 254 -- .../legacy/rest/client/UrlPostTask.java | 140 - .../legacy/rest/json/BooleanDeserializer.java | 96 - .../rest/json/ConditionDeserializer.java | 74 - .../rest/json/MatrixFieldNamingStrategy.java | 58 - .../legacy/rest/model/AuthParams.java | 33 - .../legacy/rest/model/BannedUser.java | 24 - .../legacy/rest/model/BulkLookupParams.java | 26 - .../legacy/rest/model/BulkLookupResponse.java | 26 - .../rest/model/ChangePasswordParams.java | 26 - .../legacy/rest/model/ChunkEvents.java | 20 - .../legacy/rest/model/ChunkResponse.java | 25 - .../legacy/rest/model/ContentResponse.java | 23 - .../legacy/rest/model/CreateRoomParams.java | 255 -- .../legacy/rest/model/CreateRoomResponse.java | 24 - .../legacy/rest/model/CreatedEvent.java | 24 - .../rest/model/DeactivateAccountParams.java | 26 - .../rest/model/EncryptedMediaScanBody.java | 29 - .../EncryptedMediaScanEncryptedBody.java | 29 - .../internal/legacy/rest/model/Event.java | 1339 -------- .../legacy/rest/model/EventContent.java | 49 - .../legacy/rest/model/EventContext.java | 56 - .../rest/model/ForgetPasswordParams.java | 42 - .../rest/model/ForgetPasswordResponse.java | 27 - .../internal/legacy/rest/model/HttpError.java | 44 - .../legacy/rest/model/HttpException.java | 14 - .../internal/legacy/rest/model/Invite.java | 31 - .../legacy/rest/model/MatrixError.java | 160 - .../rest/model/MediaScanPublicKeyResult.java | 27 - .../legacy/rest/model/MediaScanResult.java | 26 - .../legacy/rest/model/PowerLevels.java | 169 - .../legacy/rest/model/PushersResponse.java | 27 - .../legacy/rest/model/ReceiptData.java | 42 - .../legacy/rest/model/RedactedBecause.java | 43 - .../legacy/rest/model/RedactedContent.java | 25 - .../rest/model/ReportContentParams.java | 31 - .../model/RequestEmailValidationParams.java | 38 - .../model/RequestEmailValidationResponse.java | 34 - .../RequestPhoneNumberValidationParams.java | 38 - .../RequestPhoneNumberValidationResponse.java | 37 - .../rest/model/RoomAliasDescription.java | 33 - .../legacy/rest/model/RoomCreateContent.java | 62 - .../rest/model/RoomDirectoryVisibility.java | 24 - .../legacy/rest/model/RoomMember.java | 349 -- .../rest/model/RoomPinnedEventsContent.java | 40 - .../internal/legacy/rest/model/RoomTags.java | 24 - .../rest/model/RoomTombstoneContent.java | 40 - .../model/ServerNoticeUsageLimitContent.java | 39 - .../internal/legacy/rest/model/Signed.java | 36 - .../legacy/rest/model/StateEvent.java | 50 - .../legacy/rest/model/ThreePidCreds.java | 31 - .../legacy/rest/model/TokensChunkEvents.java | 28 - .../rest/model/TokensChunkResponse.java | 25 - .../internal/legacy/rest/model/Typing.java | 24 - .../legacy/rest/model/URLPreview.java | 124 - .../legacy/rest/model/UnsignedData.java | 44 - .../internal/legacy/rest/model/User.java | 279 -- .../internal/legacy/rest/model/Versions.java | 36 - .../legacy/rest/model/bingrules/BingRule.java | 361 -- .../rest/model/bingrules/Condition.java | 49 - .../ContainsDisplayNameCondition.java | 41 - .../rest/model/bingrules/ContentRule.java | 25 - .../rest/model/bingrules/DeviceCondition.java | 29 - .../model/bingrules/EventMatchCondition.java | 113 - .../rest/model/bingrules/PushRuleSet.java | 205 -- .../model/bingrules/PushRulesResponse.java | 21 - .../bingrules/RoomMemberCountCondition.java | 102 - ...SenderNotificationPermissionCondition.java | 37 - .../model/bingrules/UnknownCondition.java | 36 - .../model/crypto/EncryptedBodyFileInfo.java | 35 - .../model/crypto/EncryptedEventContent.java | 47 - .../rest/model/crypto/EncryptedFileInfo.java | 50 - .../rest/model/crypto/EncryptedFileKey.java | 47 - .../model/crypto/ForwardedRoomKeyContent.java | 37 - .../rest/model/crypto/KeyChangesResponse.java | 29 - .../rest/model/crypto/KeysClaimResponse.java | 30 - .../rest/model/crypto/KeysQueryResponse.java | 37 - .../rest/model/crypto/KeysUploadResponse.java | 62 - .../rest/model/crypto/NewDeviceContent.java | 28 - .../rest/model/crypto/OlmEventContent.java | 38 - .../rest/model/crypto/OlmPayloadContent.java | 48 - .../rest/model/crypto/RoomKeyContent.java | 33 - .../rest/model/crypto/RoomKeyRequest.java | 32 - .../rest/model/crypto/RoomKeyRequestBody.java | 29 - .../rest/model/filter/RoomEventFilter.java | 69 - .../group/AcceptGroupInvitationParams.java | 22 - .../rest/model/group/AddGroupParams.java | 22 - .../rest/model/group/CreateGroupParams.java | 32 - .../rest/model/group/CreateGroupResponse.java | 26 - .../rest/model/group/GetGroupsResponse.java | 28 - .../group/GetPublicisedGroupsResponse.java | 29 - .../GetUserPublicisedGroupsResponse.java | 28 - .../legacy/rest/model/group/Group.java | 277 -- .../model/group/GroupInviteUserParams.java | 22 - .../model/group/GroupInviteUserResponse.java | 30 - .../rest/model/group/GroupKickUserParams.java | 22 - .../legacy/rest/model/group/GroupProfile.java | 46 - .../legacy/rest/model/group/GroupRoom.java | 41 - .../legacy/rest/model/group/GroupRooms.java | 53 - .../legacy/rest/model/group/GroupSummary.java | 43 - .../model/group/GroupSummaryRoomsSection.java | 32 - .../rest/model/group/GroupSummaryUser.java | 34 - .../model/group/GroupSummaryUsersSection.java | 32 - .../rest/model/group/GroupSyncProfile.java | 34 - .../legacy/rest/model/group/GroupUser.java | 56 - .../legacy/rest/model/group/GroupUsers.java | 71 - .../rest/model/group/GroupsSyncResponse.java | 39 - .../rest/model/group/InvitedGroupSync.java | 34 - .../rest/model/group/LeaveGroupParams.java | 22 - .../model/group/UpdatePubliciseParams.java | 26 - .../legacy/rest/model/login/Credentials.java | 78 - .../legacy/rest/model/login/LoginFlow.java | 26 - .../rest/model/login/LoginFlowResponse.java | 25 - .../legacy/rest/model/login/LoginParams.java | 23 - .../rest/model/login/PasswordLoginParams.java | 146 - .../model/login/RegistrationFlowResponse.java | 47 - .../rest/model/login/RegistrationParams.java | 46 - .../rest/model/login/TokenLoginParams.java | 16 - .../rest/model/login/TokenRefreshParams.java | 7 - .../model/login/TokenRefreshResponse.java | 8 - .../rest/model/message/AudioMessage.java | 25 - .../legacy/rest/model/message/FileInfo.java | 33 - .../rest/model/message/FileMessage.java | 111 - .../legacy/rest/model/message/ImageInfo.java | 63 - .../rest/model/message/ImageMessage.java | 131 - .../rest/model/message/LocationMessage.java | 74 - .../rest/model/message/MediaMessage.java | 106 - .../legacy/rest/model/message/Message.java | 44 - .../legacy/rest/model/message/RelatesTo.java | 26 - .../model/message/StickerJsonMessage.java | 28 - .../rest/model/message/StickerMessage.java | 53 - .../rest/model/message/ThumbnailInfo.java | 39 - .../legacy/rest/model/message/VideoInfo.java | 54 - .../rest/model/message/VideoMessage.java | 108 - .../model/pid/AccountThreePidsResponse.java | 25 - .../rest/model/pid/AddThreePidsParams.java | 31 - .../rest/model/pid/DeleteDeviceAuth.java | 30 - .../rest/model/pid/DeleteDeviceParams.java | 23 - .../rest/model/pid/DeleteThreePidParams.java | 29 - .../legacy/rest/model/pid/Invite3Pid.java | 39 - .../legacy/rest/model/pid/PidResponse.java | 20 - .../rest/model/pid/RoomThirdPartyInvite.java | 65 - .../rest/model/pid/ThirdPartyIdentifier.java | 45 - .../rest/model/pid/ThirdPartyProtocol.java | 36 - .../model/pid/ThirdPartyProtocolInstance.java | 43 - .../legacy/rest/model/pid/ThreePid.java | 293 -- .../rest/model/publicroom/PublicRoom.java | 53 - .../model/publicroom/PublicRoomsFilter.java | 26 - .../model/publicroom/PublicRoomsParams.java | 47 - .../model/publicroom/PublicRoomsResponse.java | 43 - .../rest/model/search/SearchCategories.java | 28 - .../rest/model/search/SearchEventContext.java | 53 - .../legacy/rest/model/search/SearchGroup.java | 30 - .../rest/model/search/SearchGroupContent.java | 38 - .../rest/model/search/SearchParams.java | 27 - .../rest/model/search/SearchResponse.java | 28 - .../rest/model/search/SearchResult.java | 40 - .../search/SearchRoomEventCategoryParams.java | 37 - .../model/search/SearchRoomEventResults.java | 56 - .../rest/model/search/SearchUserProfile.java | 31 - .../rest/model/search/SearchUsersParams.java | 27 - .../search/SearchUsersRequestResponse.java | 38 - .../model/search/SearchUsersResponse.java | 32 - .../legacy/rest/model/sync/DeviceInfo.java | 70 - .../rest/model/sync/DeviceListResponse.java | 29 - .../DeviceOneTimeKeysCountSyncResponse.java | 23 - .../rest/model/sync/DevicesListResponse.java | 25 - .../rest/model/sync/InvitedRoomSync.java | 33 - .../rest/model/sync/PresenceSyncResponse.java | 30 - .../rest/model/sync/RoomInviteState.java | 30 - .../legacy/rest/model/sync/RoomResponse.java | 57 - .../legacy/rest/model/sync/RoomSync.java | 54 - .../rest/model/sync/RoomSyncAccountData.java | 29 - .../rest/model/sync/RoomSyncEphemeral.java | 29 - .../legacy/rest/model/sync/RoomSyncState.java | 31 - .../rest/model/sync/RoomSyncSummary.java | 52 - .../rest/model/sync/RoomSyncTimeline.java | 43 - .../sync/RoomSyncUnreadNotifications.java | 41 - .../rest/model/sync/RoomsSyncResponse.java | 38 - .../legacy/rest/model/sync/SyncResponse.java | 67 - .../rest/model/sync/ToDeviceSyncResponse.java | 31 - .../sync/DefaultEventsThreadListener.java | 50 - .../internal/legacy/sync/EventsThread.java | 707 ---- .../legacy/sync/EventsThreadListener.java | 49 - .../legacy/util/BingRulesManager.java | 1106 ------- .../internal/legacy/util/CompatUtil.java | 319 -- .../internal/legacy/util/ContentManager.java | 239 -- .../internal/legacy/util/ContentUtils.java | 187 -- .../internal/legacy/util/EventDisplay.java | 620 ---- .../internal/legacy/util/EventUtils.java | 127 - .../internal/legacy/util/FilterUtil.java | 152 - .../internal/legacy/util/ImageUtils.java | 335 -- .../internal/legacy/util/JsonUtils.java | 674 ---- .../android/internal/legacy/util/Log.java | 306 -- .../internal/legacy/util/MXOsHandler.java | 64 - .../internal/legacy/util/PermalinkUtils.java | 103 - .../util/PolymorphicRequestBodyConverter.java | 61 - .../internal/legacy/util/ResourceUtils.java | 192 -- .../legacy/util/SecretKeyAndVersion.java | 57 - .../legacy/util/UnsentEventsManager.java | 575 ---- .../internal/legacy/util/VersionsUtil.java | 42 - .../legacy/view/AutoScrollDownListView.java | 88 - .../internal/legacy/view/HtmlTagHandler.java | 315 -- .../internal/network/ssl/TLSSocketFactory.kt | 4 +- .../Filter.java => session/filter/Filter.kt} | 42 +- .../filter/FilterBody.kt} | 41 +- .../filter/FilterResponse.kt} | 14 +- .../session/filter/RoomEventFilter.kt | 57 + .../filter/RoomFilter.kt} | 42 +- .../room/timeline/GetContextOfEventRequest.kt | 2 +- .../room/timeline/PaginationRequest.kt | 2 +- .../internal/session/sync/GroupSyncHandler.kt | 4 +- .../internal/session/sync/SyncRequest.kt | 4 +- .../session/sync/model/SyncResponse.kt | 4 +- .../android/internal/util/FilterUtil.kt | 140 + 351 files changed, 261 insertions(+), 68651 deletions(-) delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/MXDataHandler.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/MXPatterns.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/MXSession.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/MxEventDispatcher.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/RestClient.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/CallSoundsManager.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/HeadsetConnectionReceiver.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/IMXCall.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/IMXCallListener.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/IMXCallsManagerListener.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/MXCall.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/MXCallListener.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/MXCallsManager.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/MXCallsManagerListener.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/MXChromeCall.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/MXWebRtcCall.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/MXWebRtcView.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/VideoLayoutConfiguration.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/IncomingRoomKeyRequest.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/IncomingRoomKeyRequestCancellation.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXCrypto.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXCryptoAlgorithms.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXCryptoConfig.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXCryptoError.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXDecryptionException.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXDeviceList.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXEncryptedAttachments.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXEventDecryptionResult.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXMegolmExportEncryption.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXOlmDevice.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXOutgoingRoomKeyRequestManager.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/OutgoingRoomKeyRequest.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/IMXDecrypting.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/IMXEncrypting.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/MXDecryptionResult.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/megolm/MXMegolmDecryption.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/megolm/MXMegolmEncryption.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/megolm/MXOutboundSessionInfo.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/olm/MXOlmDecryption.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/olm/MXOlmEncryption.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXDeviceInfo.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXEncryptEventContentResult.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXKey.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXOlmInboundGroupSession.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXOlmInboundGroupSession2.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXOlmSessionResult.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXQueuedEncryption.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXUsersDevicesMap.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/DataRetriever.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/MyUser.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/Pusher.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/Room.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomAccountData.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomEmailInvitation.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomMediaMessage.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomMediaMessagesSender.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomPreviewData.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomState.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomSummary.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomTag.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/comparator/Comparators.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/comparator/RoomComparatorWithTag.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/cryptostore/IMXCryptoStore.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/cryptostore/MXFileCryptoStore.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/cryptostore/MXFileCryptoStoreMetaData.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/cryptostore/MXFileCryptoStoreMetaData2.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/metrics/MetricsListener.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/store/IMXStore.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/store/IMXStoreListener.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/store/MXFileStore.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/store/MXFileStoreMetaData.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/store/MXMemoryStore.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/store/MXStoreListener.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/EventTimeline.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/EventTimelineFactory.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/MXEventTimeline.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/StateEventRedactionChecker.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/TimelineEventListeners.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/TimelineEventSaver.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/TimelineInvitedRoomSyncHandler.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/TimelineJoinRoomSyncHandler.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/TimelineLiveEventHandler.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/TimelinePushWorker.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/TimelineStateHolder.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/db/MXLatestChatMessageCache.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/db/MXMediaDownloadWorkerTask.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/db/MXMediaUploadWorkerTask.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/db/MXMediasCache.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/groups/GroupsManager.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/interfaces/DatedObject.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/interfaces/HtmlToolbox.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/IMXEventListener.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/IMXMediaDownloadListener.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/IMXMediaUploadListener.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/IMXNetworkEventListener.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/MXEventListener.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/MXMediaDownloadListener.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/MXMediaUploadListener.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/MXRoomEventListener.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/network/NetworkConnectivityReceiver.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/AccountDataApi.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/CallRulesApi.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/CryptoApi.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/EventsApi.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/FilterApi.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/GroupsApi.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/LoginApi.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/MediaScanApi.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/PresenceApi.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/ProfileApi.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/PushRulesApi.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/PushersApi.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/RoomsApi.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/ThirdPidApi.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/ApiCallback.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/ApiFailureCallback.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/DefaultRetrofit2CallbackWrapper.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/DefaultRetrofit2ResponseHandler.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/RestAdapterCallback.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/SimpleApiCallback.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/SuccessCallback.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/ToastErrorHandler.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/AccountDataRestClient.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/CallRestClient.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/CryptoRestClient.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/EventsRestClient.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/FilterRestClient.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/GroupsRestClient.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/LoginRestClient.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/MXRestExecutorService.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/MediaScanRestClient.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/PresenceRestClient.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/ProfileRestClient.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/PushRulesRestClient.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/PushersRestClient.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/RoomsRestClient.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/ThirdPidRestClient.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/UrlPostTask.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/json/BooleanDeserializer.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/json/ConditionDeserializer.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/json/MatrixFieldNamingStrategy.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/AuthParams.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/BannedUser.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/BulkLookupParams.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/BulkLookupResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ChangePasswordParams.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ChunkEvents.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ChunkResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ContentResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/CreateRoomParams.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/CreateRoomResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/CreatedEvent.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/DeactivateAccountParams.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/EncryptedMediaScanBody.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/EncryptedMediaScanEncryptedBody.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/Event.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/EventContent.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/EventContext.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ForgetPasswordParams.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ForgetPasswordResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/HttpError.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/HttpException.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/Invite.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/MatrixError.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/MediaScanPublicKeyResult.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/MediaScanResult.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/PowerLevels.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/PushersResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ReceiptData.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RedactedBecause.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RedactedContent.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ReportContentParams.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RequestEmailValidationParams.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RequestEmailValidationResponse.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RequestPhoneNumberValidationParams.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RequestPhoneNumberValidationResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RoomAliasDescription.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RoomCreateContent.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RoomDirectoryVisibility.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RoomMember.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RoomPinnedEventsContent.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RoomTags.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RoomTombstoneContent.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ServerNoticeUsageLimitContent.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/Signed.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/StateEvent.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ThreePidCreds.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/TokensChunkEvents.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/TokensChunkResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/Typing.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/URLPreview.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/UnsignedData.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/User.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/Versions.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/BingRule.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/Condition.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/ContainsDisplayNameCondition.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/ContentRule.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/DeviceCondition.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/EventMatchCondition.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/PushRuleSet.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/PushRulesResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/RoomMemberCountCondition.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/SenderNotificationPermissionCondition.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/UnknownCondition.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/EncryptedBodyFileInfo.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/EncryptedEventContent.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/EncryptedFileInfo.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/EncryptedFileKey.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/ForwardedRoomKeyContent.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/KeyChangesResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/KeysClaimResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/KeysQueryResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/KeysUploadResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/NewDeviceContent.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/OlmEventContent.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/OlmPayloadContent.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/RoomKeyContent.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/RoomKeyRequest.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/RoomKeyRequestBody.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/filter/RoomEventFilter.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/AcceptGroupInvitationParams.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/AddGroupParams.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/CreateGroupParams.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/CreateGroupResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GetGroupsResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GetPublicisedGroupsResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GetUserPublicisedGroupsResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/Group.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupInviteUserParams.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupInviteUserResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupKickUserParams.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupProfile.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupRoom.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupRooms.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupSummary.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupSummaryRoomsSection.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupSummaryUser.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupSummaryUsersSection.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupSyncProfile.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupUser.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupUsers.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupsSyncResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/InvitedGroupSync.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/LeaveGroupParams.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/UpdatePubliciseParams.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/Credentials.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/LoginFlow.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/LoginFlowResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/LoginParams.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/PasswordLoginParams.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/RegistrationFlowResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/RegistrationParams.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/TokenLoginParams.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/TokenRefreshParams.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/TokenRefreshResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/AudioMessage.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/FileInfo.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/FileMessage.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/ImageInfo.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/ImageMessage.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/LocationMessage.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/MediaMessage.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/Message.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/RelatesTo.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/StickerJsonMessage.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/StickerMessage.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/ThumbnailInfo.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/VideoInfo.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/VideoMessage.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/AccountThreePidsResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/AddThreePidsParams.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/DeleteDeviceAuth.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/DeleteDeviceParams.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/DeleteThreePidParams.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/Invite3Pid.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/PidResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/RoomThirdPartyInvite.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/ThirdPartyIdentifier.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/ThirdPartyProtocol.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/ThirdPartyProtocolInstance.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/ThreePid.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/publicroom/PublicRoom.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/publicroom/PublicRoomsFilter.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/publicroom/PublicRoomsParams.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/publicroom/PublicRoomsResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchCategories.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchEventContext.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchGroup.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchGroupContent.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchParams.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchResult.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchRoomEventCategoryParams.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchRoomEventResults.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchUserProfile.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchUsersParams.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchUsersRequestResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchUsersResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/DeviceInfo.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/DeviceListResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/DeviceOneTimeKeysCountSyncResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/DevicesListResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/InvitedRoomSync.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/PresenceSyncResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomInviteState.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomSync.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomSyncAccountData.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomSyncEphemeral.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomSyncState.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomSyncSummary.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomSyncTimeline.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomSyncUnreadNotifications.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomsSyncResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/SyncResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/ToDeviceSyncResponse.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/sync/DefaultEventsThreadListener.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/sync/EventsThread.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/sync/EventsThreadListener.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/BingRulesManager.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/CompatUtil.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/ContentManager.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/ContentUtils.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/EventDisplay.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/EventUtils.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/FilterUtil.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/ImageUtils.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/JsonUtils.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/Log.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/MXOsHandler.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/PermalinkUtils.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/PolymorphicRequestBodyConverter.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/ResourceUtils.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/SecretKeyAndVersion.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/UnsentEventsManager.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/VersionsUtil.java delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/view/AutoScrollDownListView.java delete mode 100755 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/view/HtmlTagHandler.java rename matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/{legacy/rest/model/filter/Filter.java => session/filter/Filter.kt} (55%) rename matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/{legacy/rest/model/filter/FilterBody.java => session/filter/FilterBody.kt} (53%) rename matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/{legacy/rest/model/filter/FilterResponse.java => session/filter/FilterResponse.kt} (77%) create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/RoomEventFilter.kt rename matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/{legacy/rest/model/filter/RoomFilter.java => session/filter/RoomFilter.kt} (55%) create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/FilterUtil.kt diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/MXDataHandler.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/MXDataHandler.java deleted file mode 100644 index 88f4532d..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/MXDataHandler.java +++ /dev/null @@ -1,2137 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy; - -import android.os.Handler; -import android.os.Looper; -import android.support.annotation.Nullable; -import android.text.TextUtils; - -import com.google.gson.Gson; -import com.google.gson.JsonElement; - -import im.vector.matrix.android.api.auth.data.Credentials; -import im.vector.matrix.android.internal.legacy.call.MXCallsManager; -import im.vector.matrix.android.internal.legacy.crypto.MXCrypto; -import im.vector.matrix.android.internal.legacy.crypto.MXCryptoError; -import im.vector.matrix.android.internal.legacy.crypto.MXDecryptionException; -import im.vector.matrix.android.internal.legacy.crypto.MXEventDecryptionResult; -import im.vector.matrix.android.internal.legacy.data.DataRetriever; -import im.vector.matrix.android.internal.legacy.data.MyUser; -import im.vector.matrix.android.internal.legacy.data.Room; -import im.vector.matrix.android.internal.legacy.data.RoomState; -import im.vector.matrix.android.internal.legacy.data.RoomSummary; -import im.vector.matrix.android.internal.legacy.data.metrics.MetricsListener; -import im.vector.matrix.android.internal.legacy.data.store.IMXStore; -import im.vector.matrix.android.internal.legacy.data.store.MXMemoryStore; -import im.vector.matrix.android.internal.legacy.data.timeline.EventTimeline; -import im.vector.matrix.android.internal.legacy.db.MXMediasCache; -import im.vector.matrix.android.internal.legacy.groups.GroupsManager; -import im.vector.matrix.android.internal.legacy.listeners.IMXEventListener; -import im.vector.matrix.android.internal.legacy.network.NetworkConnectivityReceiver; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.SimpleApiCallback; -import im.vector.matrix.android.internal.legacy.rest.client.AccountDataRestClient; -import im.vector.matrix.android.internal.legacy.rest.client.EventsRestClient; -import im.vector.matrix.android.internal.legacy.rest.client.PresenceRestClient; -import im.vector.matrix.android.internal.legacy.rest.client.ProfileRestClient; -import im.vector.matrix.android.internal.legacy.rest.client.RoomsRestClient; -import im.vector.matrix.android.internal.legacy.rest.client.ThirdPidRestClient; -import im.vector.matrix.android.internal.legacy.rest.model.ChunkEvents; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.rest.model.ReceiptData; -import im.vector.matrix.android.internal.legacy.rest.model.RoomAliasDescription; -import im.vector.matrix.android.internal.legacy.rest.model.RoomMember; -import im.vector.matrix.android.internal.legacy.rest.model.User; -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.BingRule; -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.PushRuleSet; -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.PushRulesResponse; -import im.vector.matrix.android.internal.legacy.rest.model.group.InvitedGroupSync; -import im.vector.matrix.android.internal.legacy.rest.model.sync.InvitedRoomSync; -import im.vector.matrix.android.internal.legacy.rest.model.sync.SyncResponse; -import im.vector.matrix.android.internal.legacy.util.BingRulesManager; -import im.vector.matrix.android.internal.legacy.util.JsonUtils; -import im.vector.matrix.android.internal.legacy.util.Log; -import im.vector.matrix.android.internal.network.ssl.UnrecognizedCertificateException; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * The data handler provides a layer to help manage matrix input and output. - * - */ -public class MXDataHandler { - private static final String LOG_TAG = MXDataHandler.class.getSimpleName(); - - private static final String LEFT_ROOMS_FILTER = "{\"room\":{\"timeline\":{\"limit\":1},\"include_leave\":true}}"; - - public interface RequestNetworkErrorListener { - /** - * Call there is a configuration error. - * - * @param matrixErrorCode the matrix error code - */ - void onConfigurationError(String matrixErrorCode); - - /** - * Call when the requests are rejected after a SSL update - * - * @param exception the exception - */ - void onSSLCertificateError(UnrecognizedCertificateException exception); - } - - private MxEventDispatcher mMxEventDispatcher; - - private final IMXStore mStore; - private final Credentials mCredentials; - private volatile String mInitialSyncToToken = null; - private DataRetriever mDataRetriever; - private BingRulesManager mBingRulesManager; - private MXCallsManager mCallsManager; - private MXMediasCache mMediasCache; - - private MetricsListener mMetricsListener; - - private ProfileRestClient mProfileRestClient; - private PresenceRestClient mPresenceRestClient; - private ThirdPidRestClient mThirdPidRestClient; - private RoomsRestClient mRoomsRestClient; - private EventsRestClient mEventsRestClient; - private AccountDataRestClient mAccountDataRestClient; - - private NetworkConnectivityReceiver mNetworkConnectivityReceiver; - - private MyUser mMyUser; - - // list of ignored users - // null -> not initialized - // should be retrieved from the store - private List mIgnoredUserIdsList; - - // list all the roomIds of the current direct chat rooms - private List mLocalDirectChatRoomIdsList = null; - - private boolean mIsAlive = true; - - private RequestNetworkErrorListener mRequestNetworkErrorListener; - - // the left rooms are managed - // by default, they are not supported - private boolean mAreLeftRoomsSynced; - - // - private final List> mLeftRoomsRefreshCallbacks = new ArrayList<>(); - private boolean mIsRetrievingLeftRooms; - - // the left rooms are saved in a dedicated store. - private final MXMemoryStore mLeftRoomsStore; - - // e2e decoder - private MXCrypto mCrypto; - - // the crypto is only started when the sync did not retrieve new device - private boolean mIsStartingCryptoWithInitialSync = false; - - // groups manager - private GroupsManager mGroupsManager; - - // Resource limit exceeded error - @Nullable - private MatrixError mResourceLimitExceededError; - - // tell if the lazy loading is enabled - private boolean mIsLazyLoadingEnabled; - - /** - * Default constructor. - * - * @param store the data storage implementation. - * @param credentials the getCredentials - */ - public MXDataHandler(IMXStore store, Credentials credentials) { - mStore = store; - mCredentials = credentials; - mMxEventDispatcher = new MxEventDispatcher(); - mLeftRoomsStore = new MXMemoryStore(credentials, store.getContext()); - } - - public void setLazyLoadingEnabled(boolean enabled) { - mIsLazyLoadingEnabled = enabled; - } - - public boolean isLazyLoadingEnabled() { - return mIsLazyLoadingEnabled; - } - - /** - * Set the network error listener. - * - * @param requestNetworkErrorListener the network error listener - */ - public void setRequestNetworkErrorListener(RequestNetworkErrorListener requestNetworkErrorListener) { - mRequestNetworkErrorListener = requestNetworkErrorListener; - } - - /** - * Update the metrics listener - * - * @param metricsListener the metrics listener - */ - public void setMetricsListener(MetricsListener metricsListener) { - mMetricsListener = metricsListener; - } - - public GroupsManager getGroupsManager() { - return mGroupsManager; - } - - /** - * @return the getCredentials - */ - public Credentials getCredentials() { - return mCredentials; - } - - /** - * Update the profile Rest client. - * - * @param profileRestClient the REST client - */ - public void setProfileRestClient(ProfileRestClient profileRestClient) { - mProfileRestClient = profileRestClient; - } - - /** - * @return the profile REST client - */ - public ProfileRestClient getProfileRestClient() { - return mProfileRestClient; - } - - /** - * Update the presence Rest client. - * - * @param presenceRestClient the REST client - */ - public void setPresenceRestClient(PresenceRestClient presenceRestClient) { - mPresenceRestClient = presenceRestClient; - } - - /** - * @return the presence REST client - */ - public PresenceRestClient getPresenceRestClient() { - return mPresenceRestClient; - } - - /** - * Update the thirdPid Rest client. - * - * @param thirdPidRestClient the REST client - */ - public void setThirdPidRestClient(ThirdPidRestClient thirdPidRestClient) { - mThirdPidRestClient = thirdPidRestClient; - } - - /** - * @return the ThirdPid REST client - */ - public ThirdPidRestClient getThirdPidRestClient() { - return mThirdPidRestClient; - } - - /** - * Update the rooms Rest client. - * - * @param roomsRestClient the rooms client - */ - public void setRoomsRestClient(RoomsRestClient roomsRestClient) { - mRoomsRestClient = roomsRestClient; - } - - /** - * Update the events Rest client. - * - * @param eventsRestClient the events client - */ - public void setEventsRestClient(EventsRestClient eventsRestClient) { - mEventsRestClient = eventsRestClient; - } - - /** - * Update the account data Rest client. - * - * @param accountDataRestClient the account data client - */ - public void setAccountDataRestClient(AccountDataRestClient accountDataRestClient) { - mAccountDataRestClient = accountDataRestClient; - } - - /** - * Update the network connectivity receiver. - * - * @param networkConnectivityReceiver the network connectivity receiver - */ - public void setNetworkConnectivityReceiver(NetworkConnectivityReceiver networkConnectivityReceiver) { - mNetworkConnectivityReceiver = networkConnectivityReceiver; - - if (null != getCrypto()) { - getCrypto().setNetworkConnectivityReceiver(mNetworkConnectivityReceiver); - } - } - - /** - * Set the groups manager. - * - * @param groupsManager the groups manager - */ - public void setGroupsManager(GroupsManager groupsManager) { - mGroupsManager = groupsManager; - } - - /** - * @return the crypto engine - */ - public MXCrypto getCrypto() { - return mCrypto; - } - - /** - * Update the crypto engine. - * - * @param crypto the crypto engine - */ - public void setCrypto(MXCrypto crypto) { - mCrypto = crypto; - } - - /** - * @return true if the crypto is enabled - */ - public boolean isCryptoEnabled() { - return null != mCrypto; - } - - /** - * Provide the list of user Ids to ignore. - * The result cannot be null. - * - * @return the user Ids list - */ - public List getIgnoredUserIds() { - if (null == mIgnoredUserIdsList) { - mIgnoredUserIdsList = mStore.getIgnoredUserIdsList(); - } - - // avoid the null case - if (null == mIgnoredUserIdsList) { - mIgnoredUserIdsList = new ArrayList<>(); - } - - return mIgnoredUserIdsList; - } - - /** - * Test if the current instance is still active. - * When the session is closed, many objects keep a reference to this class - * to dispatch events : isAlive() should be called before calling a method of this class. - */ - private void checkIfAlive() { - synchronized (this) { - if (!mIsAlive) { - Log.e(LOG_TAG, "use of a released dataHandler", new Exception("use of a released dataHandler")); - //throw new AssertionError("Should not used a MXDataHandler"); - } - } - } - - /** - * Tell if the current instance is still active. - * When the session is closed, many objects keep a reference to this class - * to dispatch events : isAlive() should be called before calling a method of this class. - * - * @return true if it is active. - */ - public boolean isAlive() { - synchronized (this) { - return mIsAlive; - } - } - - /** - * Dispatch the configuration error. - * - * @param matrixErrorCode the matrix error code. - */ - public void onConfigurationError(String matrixErrorCode) { - if (null != mRequestNetworkErrorListener) { - mRequestNetworkErrorListener.onConfigurationError(matrixErrorCode); - } - } - - /** - * Call when the requests are rejected after a SSL update. - * - * @param exception the SSL certificate exception - */ - public void onSSLCertificateError(UnrecognizedCertificateException exception) { - if (null != mRequestNetworkErrorListener) { - mRequestNetworkErrorListener.onSSLCertificateError(exception); - } - } - - /** - * Get the last resource limit exceeded error if any or null - * - * @return the last resource limit exceeded error if any or null - */ - @Nullable - public MatrixError getResourceLimitExceededError() { - return mResourceLimitExceededError; - } - - /** - * Get the session's current user. The MyUser object provides methods for updating user properties which are not possible for other users. - * - * @return the session's MyUser object - */ - public MyUser getMyUser() { - checkIfAlive(); - - IMXStore store = getStore(); - - // MyUser is initialized as late as possible to have a better chance at having the info in storage, - // which should be the case if this is called after the initial sync - if (mMyUser == null) { - mMyUser = new MyUser(store.getUser(mCredentials.getUserId())); - mMyUser.setDataHandler(this); - - // assume the profile is not yet initialized - if (null == store.displayName()) { - store.setAvatarURL(mMyUser.getAvatarUrl(), System.currentTimeMillis()); - store.setDisplayName(mMyUser.displayname, System.currentTimeMillis()); - } else { - // use the latest user information - // The user could have updated his profile in offline mode and kill the application. - mMyUser.displayname = store.displayName(); - mMyUser.setAvatarUrl(store.avatarURL()); - } - - // Handle the case where the user is null by loading the user information from the server - mMyUser.user_id = mCredentials.getUserId(); - } else if (null != store) { - // assume the profile is not yet initialized - if ((null == store.displayName()) && (null != mMyUser.displayname)) { - // setAvatarURL && setDisplayName perform a commit if it is required. - store.setAvatarURL(mMyUser.getAvatarUrl(), System.currentTimeMillis()); - store.setDisplayName(mMyUser.displayname, System.currentTimeMillis()); - } else if (!TextUtils.equals(mMyUser.displayname, store.displayName())) { - mMyUser.displayname = store.displayName(); - mMyUser.setAvatarUrl(store.avatarURL()); - } - } - - // check if there is anything to refresh - mMyUser.refreshUserInfos(null); - - return mMyUser; - } - - /** - * @return true if the initial sync is completed. - */ - public boolean isInitialSyncComplete() { - checkIfAlive(); - return (null != mInitialSyncToToken); - } - - /** - * @return the DataRetriever. - */ - public DataRetriever getDataRetriever() { - checkIfAlive(); - return mDataRetriever; - } - - /** - * Update the dataRetriever. - * - * @param dataRetriever the dataRetriever. - */ - public void setDataRetriever(DataRetriever dataRetriever) { - checkIfAlive(); - mDataRetriever = dataRetriever; - } - - /** - * Update the push rules manager. - * - * @param bingRulesManager the new push rules manager. - */ - public void setPushRulesManager(BingRulesManager bingRulesManager) { - if (isAlive()) { - mBingRulesManager = bingRulesManager; - - mBingRulesManager.loadRules(new SimpleApiCallback() { - @Override - public void onSuccess(Void info) { - onBingRulesUpdate(); - } - }); - } - } - - /** - * Update the calls manager. - * - * @param callsManager the new calls manager. - */ - public void setCallsManager(MXCallsManager callsManager) { - checkIfAlive(); - mCallsManager = callsManager; - } - - /** - * @return the user calls manager. - */ - public MXCallsManager getCallsManager() { - checkIfAlive(); - return mCallsManager; - } - - /** - * Update the medias cache. - * - * @param mediasCache the new medias cache. - */ - public void setMediasCache(MXMediasCache mediasCache) { - checkIfAlive(); - mMediasCache = mediasCache; - } - - /** - * Retrieve the medias cache. - * - * @return the used mediasCache - */ - public MXMediasCache getMediasCache() { - checkIfAlive(); - return mMediasCache; - } - - /** - * @return the used push rules set. - */ - public PushRuleSet pushRules() { - if (isAlive() && (null != mBingRulesManager)) { - return mBingRulesManager.pushRules(); - } - - return null; - } - - /** - * Trigger a push rules refresh. - */ - public void refreshPushRules() { - if (isAlive() && (null != mBingRulesManager)) { - mBingRulesManager.loadRules(new SimpleApiCallback() { - @Override - public void onSuccess(Void info) { - onBingRulesUpdate(); - } - }); - } - } - - /** - * @return the used BingRulesManager. - */ - public BingRulesManager getBingRulesManager() { - checkIfAlive(); - return mBingRulesManager; - } - - /** - * Set the crypto events listener, or remove it - * - * @param listener the listener or null to remove the listener - */ - public void setCryptoEventsListener(@Nullable IMXEventListener listener) { - mMxEventDispatcher.setCryptoEventsListener(listener); - } - - /** - * Add a listener to the listeners list. - * - * @param listener the listener to add. - */ - public void addListener(IMXEventListener listener) { - if (isAlive() && (null != listener)) { - synchronized (mMxEventDispatcher) { - mMxEventDispatcher.addListener(listener); - } - - if (null != mInitialSyncToToken) { - listener.onInitialSyncComplete(mInitialSyncToToken); - } - } - } - - /** - * Remove a listener from the listeners list. - * - * @param listener to remove. - */ - public void removeListener(IMXEventListener listener) { - if (isAlive() && (null != listener)) { - synchronized (mMxEventDispatcher) { - mMxEventDispatcher.removeListener(listener); - } - } - } - - /** - * Clear the instance data. - */ - public void clear() { - synchronized (mMxEventDispatcher) { - mIsAlive = false; - // remove any listener - mMxEventDispatcher.clearListeners(); - } - - // clear the store - mStore.close(); - mStore.clear(); - } - - /** - * @return the current user id. - */ - public String getUserId() { - if (isAlive()) { - return mCredentials.getUserId(); - } else { - return "dummy"; - } - } - - /** - * Update the missing data fields loaded from a permanent storage. - */ - void checkPermanentStorageData() { - if (!isAlive()) { - Log.e(LOG_TAG, "checkPermanentStorageData : the session is not anymore active"); - return; - } - - // When the data are extracted from a persistent storage, - // some fields are not retrieved : - // They are used to retrieve some data - // so add the missing links. - Collection summaries = mStore.getSummaries(); - for (RoomSummary summary : summaries) { - if (null != summary.getLatestRoomState()) { - summary.getLatestRoomState().setDataHandler(this); - } - } - } - - - /** - * @return the used store. - */ - public IMXStore getStore() { - if (isAlive()) { - return mStore; - } else { - Log.e(LOG_TAG, "getStore : the session is not anymore active"); - return null; - } - } - - /** - * Provides the store in which the room is stored. - * - * @param roomId the room id - * @return the used store - */ - public IMXStore getStore(String roomId) { - if (isAlive()) { - if (null == roomId) { - return mStore; - } else { - if (null != mLeftRoomsStore.getRoom(roomId)) { - return mLeftRoomsStore; - } else { - return mStore; - } - } - } else { - Log.e(LOG_TAG, "getStore : the session is not anymore active"); - return null; - } - } - - /** - * Returns the member with userID; - * - * @param members the members List - * @param userID the user ID - * @return the roomMember if it exists. - */ - public RoomMember getMember(Collection members, String userID) { - if (isAlive()) { - for (RoomMember member : members) { - if (TextUtils.equals(userID, member.getUserId())) { - return member; - } - } - } else { - Log.e(LOG_TAG, "getMember : the session is not anymore active"); - } - return null; - } - - /** - * Check a room exists with the dedicated roomId - * - * @param roomId the room ID - * @return true it exists. - */ - public boolean doesRoomExist(String roomId) { - return (null != roomId) && (null != mStore.getRoom(roomId)); - } - - /** - * @return the left rooms - */ - public Collection getLeftRooms() { - return new ArrayList<>(mLeftRoomsStore.getRooms()); - } - - /** - * Get the room object for the corresponding room id. Creates and initializes the object if there is none. - * - * @param roomId the room id - * @return the corresponding room - */ - public Room getRoom(String roomId) { - return getRoom(roomId, true); - } - - /** - * Get the room object for the corresponding room id. - * The left rooms are not included. - * - * @param roomId the room id - * @param create create the room it does not exist. - * @return the corresponding room - */ - public Room getRoom(String roomId, boolean create) { - return getRoom(mStore, roomId, create); - } - - /** - * Get the room object for the corresponding room id. - * By default, the left rooms are not included. - * - * @param roomId the room id - * @param testLeftRooms true to test if the room is a left room - * @param create create the room it does not exist. - * @return the corresponding room - */ - public Room getRoom(String roomId, boolean testLeftRooms, boolean create) { - Room room = null; - - if (null != roomId) { - room = mStore.getRoom(roomId); - - if ((null == room) && testLeftRooms) { - room = mLeftRoomsStore.getRoom(roomId); - } - - if ((null == room) && create) { - room = getRoom(mStore, roomId, create); - } - } - - return room; - } - - /** - * Get the room object from the corresponding room id. - * - * @param store the dedicated store - * @param roomId the room id - * @param create create the room it does not exist. - * @return the corresponding room - */ - public Room getRoom(IMXStore store, String roomId, boolean create) { - if (!isAlive()) { - Log.e(LOG_TAG, "getRoom : the session is not anymore active"); - return null; - } - - // sanity check - if (TextUtils.isEmpty(roomId)) { - return null; - } - - Room room; - - synchronized (this) { - room = store.getRoom(roomId); - if ((room == null) && create) { - Log.d(LOG_TAG, "## getRoom() : create the room " + roomId); - room = new Room(this, store, roomId); - store.storeRoom(room); - } else if ((null != room) && (null == room.getDataHandler())) { - // GA reports that some rooms have no data handler - // so ensure that it is not properly set - Log.e(LOG_TAG, "getRoom " + roomId + " was not initialized"); - store.storeRoom(room); - } - } - - return room; - } - - /** - * Provides the room summaries list. - * - * @param withLeftOnes set to true to include the left rooms - * @return the room summaries - */ - public Collection getSummaries(boolean withLeftOnes) { - List summaries = new ArrayList<>(); - - summaries.addAll(getStore().getSummaries()); - - if (withLeftOnes) { - summaries.addAll(mLeftRoomsStore.getSummaries()); - } - - return summaries; - } - - /** - * Retrieve a room Id by its alias. - * - * @param roomAlias the room alias - * @param callback the asynchronous callback - */ - public void roomIdByAlias(final String roomAlias, final ApiCallback callback) { - String roomId = null; - - Collection rooms = getStore().getRooms(); - - for (Room room : rooms) { - if (TextUtils.equals(room.getState().getCanonicalAlias(), roomAlias)) { - roomId = room.getRoomId(); - break; - } else { - // getAliases cannot be null - List aliases = room.getState().getAliases(); - - for (String alias : aliases) { - if (TextUtils.equals(alias, roomAlias)) { - roomId = room.getRoomId(); - break; - } - } - - // find one matched room id. - if (null != roomId) { - break; - } - } - } - - if (null != roomId) { - final String fRoomId = roomId; - - Handler handler = new Handler(Looper.getMainLooper()); - - handler.post(new Runnable() { - @Override - public void run() { - callback.onSuccess(fRoomId); - } - }); - } else { - mRoomsRestClient.getRoomIdByAlias(roomAlias, new SimpleApiCallback(callback) { - @Override - public void onSuccess(RoomAliasDescription info) { - callback.onSuccess(info.room_id); - } - }); - } - - } - - /** - * Get the members of a Room with a request to the server. it will exclude the members who has left the room - * - * @param roomId the id of the room - * @param callback the callback - */ - public void getMembersAsync(final String roomId, final ApiCallback> callback) { - mRoomsRestClient.getRoomMembers(roomId, getStore().getEventStreamToken(), null, RoomMember.MEMBERSHIP_LEAVE, - new SimpleApiCallback(callback) { - @Override - public void onSuccess(ChunkEvents info) { - Room room = getRoom(roomId); - - if (info.chunk != null) { - for (Event event : info.chunk) { - room.getState().applyState(getStore(), event, EventTimeline.Direction.FORWARDS); - } - } - - callback.onSuccess(room.getState().getLoadedMembers()); - } - }); - } - - /** - * Delete an event. - * - * @param event The event to be stored. - */ - public void deleteRoomEvent(Event event) { - if (isAlive()) { - Room room = getRoom(event.roomId); - - if (null != room) { - mStore.deleteEvent(event); - Event lastEvent = mStore.getLatestEvent(event.roomId); - RoomState beforeLiveRoomState = room.getState().deepCopy(); - - RoomSummary summary = mStore.getSummary(event.roomId); - if (null == summary) { - summary = new RoomSummary(null, lastEvent, beforeLiveRoomState, mCredentials.getUserId()); - } else { - summary.setLatestReceivedEvent(lastEvent, beforeLiveRoomState); - } - - if (TextUtils.equals(summary.getReadReceiptEventId(), event.eventId)) { - summary.setReadReceiptEventId(lastEvent.eventId); - } - - if (TextUtils.equals(summary.getReadMarkerEventId(), event.eventId)) { - summary.setReadMarkerEventId(lastEvent.eventId); - } - - mStore.storeSummary(summary); - } - } else { - Log.e(LOG_TAG, "deleteRoomEvent : the session is not anymore active"); - } - } - - /** - * Return an user from his id. - * - * @param userId the user id;. - * @return the user. - */ - public User getUser(String userId) { - if (!isAlive()) { - Log.e(LOG_TAG, "getUser : the session is not anymore active"); - return null; - } else { - User user = mStore.getUser(userId); - - if (null == user) { - user = mLeftRoomsStore.getUser(userId); - } - - return user; - } - } - - //================================================================================ - // Account Data management - //================================================================================ - - /** - * Manage the sync accountData field - * - * @param accountData the account data - * @param isInitialSync true if it is an initial sync response - */ - private void manageAccountData(Map accountData, boolean isInitialSync) { - try { - if (accountData.containsKey("events")) { - List> events = (List>) accountData.get("events"); - - if (!events.isEmpty()) { - // ignored users list - manageIgnoredUsers(events, isInitialSync); - // push rules - managePushRulesUpdate(events); - // direct messages rooms - manageDirectChatRooms(events, isInitialSync); - // URL preview - manageUrlPreview(events); - // User widgets - manageUserWidgets(events); - } - } - } catch (Exception e) { - Log.e(LOG_TAG, "manageAccountData failed " + e.getMessage(), e); - } - } - - /** - * Refresh the push rules from the account data events list - * - * @param events the account data events. - */ - private void managePushRulesUpdate(List> events) { - for (Map event : events) { - String type = (String) event.get("type"); - - if (TextUtils.equals(type, "m.push_rules")) { - if (event.containsKey("content")) { - Gson gson = JsonUtils.getGson(false); - - // convert the data to PushRulesResponse - // because BingRulesManager supports only PushRulesResponse - JsonElement element = gson.toJsonTree(event.get("content")); - getBingRulesManager().buildRules(gson.fromJson(element, PushRulesResponse.class)); - - // warn the client that the push rules have been updated - onBingRulesUpdate(); - } - - return; - } - } - } - - /** - * Check if the ignored users list is updated - * - * @param events the account data events list - */ - private void manageIgnoredUsers(List> events, boolean isInitialSync) { - List newIgnoredUsers = ignoredUsers(events); - - if (null != newIgnoredUsers) { - List curIgnoredUsers = getIgnoredUserIds(); - - // the both lists are not empty - if ((0 != newIgnoredUsers.size()) || (0 != curIgnoredUsers.size())) { - // check if the ignored users list has been updated - if ((newIgnoredUsers.size() != curIgnoredUsers.size()) || !newIgnoredUsers.containsAll(curIgnoredUsers)) { - // update the store - mStore.setIgnoredUserIdsList(newIgnoredUsers); - mIgnoredUserIdsList = newIgnoredUsers; - - if (!isInitialSync) { - // warn there is an update - onIgnoredUsersListUpdate(); - } - } - } - } - } - - /** - * Extract the ignored users list from the account data events list.. - * - * @param events the account data events list. - * @return the ignored users list. null means that there is no defined user ids list. - */ - public List ignoredUsers(List> events) { - List ignoredUsers = null; - - if (0 != events.size()) { - for (Map event : events) { - String type = (String) event.get("type"); - - if (TextUtils.equals(type, AccountDataRestClient.ACCOUNT_DATA_TYPE_IGNORED_USER_LIST)) { - if (event.containsKey("content")) { - Map contentDict = (Map) event.get("content"); - - if (contentDict.containsKey(AccountDataRestClient.ACCOUNT_DATA_KEY_IGNORED_USERS)) { - Map ignored_users = (Map) contentDict.get(AccountDataRestClient.ACCOUNT_DATA_KEY_IGNORED_USERS); - - if (null != ignored_users) { - ignoredUsers = new ArrayList<>(ignored_users.keySet()); - } - } - } - } - } - - } - - return ignoredUsers; - } - - - /** - * Extract the direct chat rooms list from the dedicated events. - * - * @param events the account data events list. - */ - private void manageDirectChatRooms(List> events, boolean isInitialSync) { - if (0 != events.size()) { - for (Map event : events) { - String type = (String) event.get("type"); - - if (TextUtils.equals(type, AccountDataRestClient.ACCOUNT_DATA_TYPE_DIRECT_MESSAGES)) { - if (event.containsKey("content")) { - Map> contentDict = (Map>) event.get("content"); - - Log.d(LOG_TAG, "## manageDirectChatRooms() : update direct chats map" + contentDict); - - mStore.setDirectChatRoomsDict(contentDict); - - // reset the current list of the direct chat roomIDs - // to update it - mLocalDirectChatRoomIdsList = null; - - if (!isInitialSync) { - // warn there is an update - onDirectMessageChatRoomsListUpdate(); - } - } - } - } - } - } - - /** - * Manage the URL preview flag - * - * @param events the events list - */ - private void manageUrlPreview(List> events) { - if (0 != events.size()) { - for (Map event : events) { - String type = (String) event.get("type"); - - if (TextUtils.equals(type, AccountDataRestClient.ACCOUNT_DATA_TYPE_PREVIEW_URLS)) { - if (event.containsKey("content")) { - Map contentDict = (Map) event.get("content"); - - Log.d(LOG_TAG, "## manageUrlPreview() : " + contentDict); - boolean enable = true; - if (contentDict.containsKey(AccountDataRestClient.ACCOUNT_DATA_KEY_URL_PREVIEW_DISABLE)) { - enable = !((boolean) contentDict.get(AccountDataRestClient.ACCOUNT_DATA_KEY_URL_PREVIEW_DISABLE)); - } - - mStore.setURLPreviewEnabled(enable); - } - } - } - } - } - - /** - * Manage the user widgets - * - * @param events the events list - */ - private void manageUserWidgets(List> events) { - if (0 != events.size()) { - for (Map event : events) { - String type = (String) event.get("type"); - - if (TextUtils.equals(type, AccountDataRestClient.ACCOUNT_DATA_TYPE_WIDGETS)) { - if (event.containsKey("content")) { - Map contentDict = (Map) event.get("content"); - - Log.d(LOG_TAG, "## manageUserWidgets() : " + contentDict); - - mStore.setUserWidgets(contentDict); - } - } - } - } - } - - //================================================================================ - // Sync V2 - //================================================================================ - - /** - * Handle a presence event. - * - * @param presenceEvent the presence event. - */ - private void handlePresenceEvent(Event presenceEvent) { - // Presence event - if (Event.EVENT_TYPE_PRESENCE.equals(presenceEvent.getType())) { - User userPresence = JsonUtils.toUser(presenceEvent.getContent()); - - // use the sender by default - if (!TextUtils.isEmpty(presenceEvent.getSender())) { - userPresence.user_id = presenceEvent.getSender(); - } - - User user = mStore.getUser(userPresence.user_id); - - if (user == null) { - user = userPresence; - user.setDataHandler(this); - } else { - user.currently_active = userPresence.currently_active; - user.presence = userPresence.presence; - user.lastActiveAgo = userPresence.lastActiveAgo; - } - - user.setLatestPresenceTs(System.currentTimeMillis()); - - // check if the current user has been updated - if (mCredentials.getUserId().equals(user.user_id)) { - // always use the up-to-date information - getMyUser().displayname = user.displayname; - getMyUser().avatar_url = user.getAvatarUrl(); - - mStore.setAvatarURL(user.getAvatarUrl(), presenceEvent.getOriginServerTs()); - mStore.setDisplayName(user.displayname, presenceEvent.getOriginServerTs()); - } - - mStore.storeUser(user); - onPresenceUpdate(presenceEvent, user); - } - } - - /** - * Manage a syncResponse. - * - * @param syncResponse the syncResponse to manage. - * @param fromToken the start sync token - * @param isCatchingUp true when there is a pending catch-up - */ - public void onSyncResponse(final SyncResponse syncResponse, final String fromToken, final boolean isCatchingUp) { - manageResponse(syncResponse, fromToken, isCatchingUp); - } - - /** - * Delete a room from its room id. - * The room data is copied into the left rooms store. - * - * @param roomId the room id - */ - public void deleteRoom(String roomId) { - // copy the room from a store to another one - Room r = getStore().getRoom(roomId); - - if (null != r) { - if (mAreLeftRoomsSynced) { - Room leftRoom = getRoom(mLeftRoomsStore, roomId, true); - leftRoom.setIsLeft(true); - - // copy the summary - RoomSummary summary = getStore().getSummary(roomId); - if (null != summary) { - mLeftRoomsStore.storeSummary(new RoomSummary(summary, summary.getLatestReceivedEvent(), summary.getLatestRoomState(), getUserId())); - } - - // copy events and receiptData - // it is not required but it is better, it could be useful later - // the room summary should be enough to be displayed in the recent pages - List receipts = new ArrayList<>(); - Collection events = getStore().getRoomMessages(roomId); - - if (null != events) { - for (Event e : events) { - receipts.addAll(getStore().getEventReceipts(roomId, e.eventId, false, false)); - mLeftRoomsStore.storeLiveRoomEvent(e); - } - - for (ReceiptData receipt : receipts) { - mLeftRoomsStore.storeReceipt(receipt, roomId); - } - } - - // copy the state - leftRoom.getTimeline().setState(r.getTimeline().getState()); - } - - // remove the previous definition - getStore().deleteRoom(roomId); - } - } - - /** - * Manage the sync response in a background thread. - * - * @param syncResponse the syncResponse to manage. - * @param fromToken the start sync token - * @param isCatchingUp true when there is a pending catch-up - */ - public void manageResponse(final SyncResponse syncResponse, final String fromToken, final boolean isCatchingUp) { - if (!isAlive()) { - Log.e(LOG_TAG, "manageResponse : ignored because the session has been closed"); - return; - } - - boolean isInitialSync = (null == fromToken); - boolean isEmptyResponse = true; - - // sanity check - if (null != syncResponse) { - Log.d(LOG_TAG, "onSyncComplete"); - - // Handle the to device events before the room ones - // to ensure to decrypt them properly - if ((null != syncResponse.toDevice) - && (null != syncResponse.toDevice.events) - && (syncResponse.toDevice.events.size() > 0)) { - Log.d(LOG_TAG, "manageResponse : receives " + syncResponse.toDevice.events.size() + " toDevice events"); - - for (Event toDeviceEvent : syncResponse.toDevice.events) { - handleToDeviceEvent(toDeviceEvent); - } - } - - // Handle account data before the room events - // to be able to update direct chats dictionary during invites handling. - if (null != syncResponse.accountData) { - Log.d(LOG_TAG, "Received " + syncResponse.accountData.size() + " accountData events"); - manageAccountData(syncResponse.accountData, isInitialSync); - } - - // sanity check - if (null != syncResponse.rooms) { - // joined rooms events - if ((null != syncResponse.rooms.join) && (syncResponse.rooms.join.size() > 0)) { - Log.d(LOG_TAG, "Received " + syncResponse.rooms.join.size() + " joined rooms"); - if (mMetricsListener != null) { - mMetricsListener.onRoomsLoaded(syncResponse.rooms.join.size()); - } - Set roomIds = syncResponse.rooms.join.keySet(); - // Handle first joined rooms - for (String roomId : roomIds) { - try { - if (null != mLeftRoomsStore.getRoom(roomId)) { - Log.d(LOG_TAG, "the room " + roomId + " moves from left to the joined ones"); - mLeftRoomsStore.deleteRoom(roomId); - } - - getRoom(roomId).handleJoinedRoomSync(syncResponse.rooms.join.get(roomId), isInitialSync); - } catch (Exception e) { - Log.e(LOG_TAG, "## manageResponse() : handleJoinedRoomSync failed " + e.getMessage() + " for room " + roomId, e); - } - } - - isEmptyResponse = false; - } - - // invited room management - if ((null != syncResponse.rooms.invite) && (syncResponse.rooms.invite.size() > 0)) { - Log.d(LOG_TAG, "Received " + syncResponse.rooms.invite.size() + " invited rooms"); - - Set roomIds = syncResponse.rooms.invite.keySet(); - - Map> updatedDirectChatRoomsDict = null; - boolean hasChanged = false; - - for (String roomId : roomIds) { - try { - Log.d(LOG_TAG, "## manageResponse() : the user has been invited to " + roomId); - - if (null != mLeftRoomsStore.getRoom(roomId)) { - Log.d(LOG_TAG, "the room " + roomId + " moves from left to the invited ones"); - mLeftRoomsStore.deleteRoom(roomId); - } - - Room room = getRoom(roomId); - InvitedRoomSync invitedRoomSync = syncResponse.rooms.invite.get(roomId); - - room.handleInvitedRoomSync(invitedRoomSync); - - // Handle here the invites to a direct chat. - if (room.isDirectChatInvitation()) { - // Retrieve the inviter user id. - String participantUserId = null; - for (Event event : invitedRoomSync.inviteState.events) { - if (null != event.sender) { - participantUserId = event.sender; - break; - } - } - - if (null != participantUserId) { - // Prepare the updated dictionary. - if (null == updatedDirectChatRoomsDict) { - if (null != getStore().getDirectChatRoomsDict()) { - // Consider the current dictionary. - updatedDirectChatRoomsDict = new HashMap<>(getStore().getDirectChatRoomsDict()); - } else { - updatedDirectChatRoomsDict = new HashMap<>(); - } - } - - List roomIdsList; - if (updatedDirectChatRoomsDict.containsKey(participantUserId)) { - roomIdsList = new ArrayList<>(updatedDirectChatRoomsDict.get(participantUserId)); - } else { - roomIdsList = new ArrayList<>(); - } - - // Check whether the room was not yet seen as direct chat - if (roomIdsList.indexOf(roomId) < 0) { - Log.d(LOG_TAG, "## manageResponse() : add this new invite in direct chats"); - - roomIdsList.add(roomId); // update room list with the new room - updatedDirectChatRoomsDict.put(participantUserId, roomIdsList); - hasChanged = true; - } - } - } - } catch (Exception e) { - Log.e(LOG_TAG, "## manageResponse() : handleInvitedRoomSync failed " + e.getMessage() + " for room " + roomId, e); - } - } - - isEmptyResponse = false; - - if (hasChanged) { - // Update account data to add new direct chat room(s) - mAccountDataRestClient.setAccountData(mCredentials.getUserId(), AccountDataRestClient.ACCOUNT_DATA_TYPE_DIRECT_MESSAGES, - updatedDirectChatRoomsDict, new ApiCallback() { - @Override - public void onSuccess(Void info) { - Log.d(LOG_TAG, "## manageResponse() : succeeds"); - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "## manageResponse() : update account data failed " + e.getMessage(), e); - // TODO: we should try again. - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "## manageResponse() : update account data failed " + e.getMessage()); - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "## manageResponse() : update account data failed " + e.getMessage(), e); - } - }); - } - } - - // left room management - // it should be done at the end but it seems there is a server issue - // when inviting after leaving a room, the room is defined in the both leave & invite rooms list. - if ((null != syncResponse.rooms.leave) && (syncResponse.rooms.leave.size() > 0)) { - Log.d(LOG_TAG, "Received " + syncResponse.rooms.leave.size() + " left rooms"); - - Set roomIds = syncResponse.rooms.leave.keySet(); - - for (String roomId : roomIds) { - // RoomSync leftRoomSync = syncResponse.rooms.leave.get(roomId); - - // Presently we remove the existing room from the rooms list. - // FIXME SYNC V2 Archive/Display the left rooms! - // For that create 'handleArchivedRoomSync' method - - String membership = RoomMember.MEMBERSHIP_LEAVE; - Room room = getRoom(roomId); - - // Retrieve existing room - // check if the room still exists. - if (null != room) { - // use 'handleJoinedRoomSync' to pass the last events to the room before leaving it. - // The room will then be able to notify its listeners. - room.handleJoinedRoomSync(syncResponse.rooms.leave.get(roomId), isInitialSync); - - RoomMember member = room.getMember(getUserId()); - if (null != member) { - membership = member.membership; - } - - Log.d(LOG_TAG, "## manageResponse() : leave the room " + roomId); - } - - if (!TextUtils.equals(membership, RoomMember.MEMBERSHIP_KICK) && !TextUtils.equals(membership, RoomMember.MEMBERSHIP_BAN)) { - // ensure that the room data are properly deleted - getStore().deleteRoom(roomId); - onLeaveRoom(roomId); - } else { - onRoomKick(roomId); - } - - // don't add to the left rooms if the user has been kicked / banned - if ((mAreLeftRoomsSynced) && TextUtils.equals(membership, RoomMember.MEMBERSHIP_LEAVE)) { - Room leftRoom = getRoom(mLeftRoomsStore, roomId, true); - leftRoom.handleJoinedRoomSync(syncResponse.rooms.leave.get(roomId), isInitialSync); - } - } - - isEmptyResponse = false; - } - } - - // groups - if (null != syncResponse.groups) { - // Handle invited groups - if ((null != syncResponse.groups.invite) && !syncResponse.groups.invite.isEmpty()) { - // Handle invited groups - for (String groupId : syncResponse.groups.invite.keySet()) { - InvitedGroupSync invitedGroupSync = syncResponse.groups.invite.get(groupId); - mGroupsManager.onNewGroupInvitation(groupId, invitedGroupSync.profile, invitedGroupSync.inviter, !isInitialSync); - } - } - - // Handle joined groups - if ((null != syncResponse.groups.join) && !syncResponse.groups.join.isEmpty()) { - for (String groupId : syncResponse.groups.join.keySet()) { - mGroupsManager.onJoinGroup(groupId, !isInitialSync); - } - } - // Handle left groups - if ((null != syncResponse.groups.leave) && !syncResponse.groups.leave.isEmpty()) { - // Handle joined groups - for (String groupId : syncResponse.groups.leave.keySet()) { - mGroupsManager.onLeaveGroup(groupId, !isInitialSync); - } - } - } - - // Handle presence of other users - if ((null != syncResponse.presence) && (null != syncResponse.presence.events)) { - Log.d(LOG_TAG, "Received " + syncResponse.presence.events.size() + " presence events"); - for (Event presenceEvent : syncResponse.presence.events) { - handlePresenceEvent(presenceEvent); - } - } - - IMXStore store = getStore(); - - if (!isEmptyResponse && (null != store)) { - store.setEventStreamToken(syncResponse.nextBatch); - store.commit(); - } - } - - if (isInitialSync) { - if (!isCatchingUp) { - startCrypto(true); - } else { - // the events thread sends a dummy initial sync event - // when the application is restarted. - mIsStartingCryptoWithInitialSync = !isEmptyResponse; - } - - onInitialSyncComplete((null != syncResponse) ? syncResponse.nextBatch : null); - } else { - - if (!isCatchingUp) { - startCrypto(mIsStartingCryptoWithInitialSync); - } - - try { - onLiveEventsChunkProcessed(fromToken, (null != syncResponse) ? syncResponse.nextBatch : fromToken); - } catch (Exception e) { - Log.e(LOG_TAG, "onLiveEventsChunkProcessed failed " + e.getMessage(), e); - } - - try { - // check if an incoming call has been received - mCallsManager.checkPendingIncomingCalls(); - } catch (Exception e) { - Log.e(LOG_TAG, "checkPendingIncomingCalls failed " + e + " " + e.getMessage(), e); - } - } - } - - /** - * Refresh the unread summary counters of the updated rooms. - */ - private void refreshUnreadCounters() { - Set roomIdsList; - - synchronized (mUpdatedRoomIdList) { - roomIdsList = new HashSet<>(mUpdatedRoomIdList); - mUpdatedRoomIdList.clear(); - } - // refresh the unread counter - for (String roomId : roomIdsList) { - Room room = mStore.getRoom(roomId); - - if (null != room) { - room.refreshUnreadCounter(); - } - } - } - - /** - * @return true if the historical rooms loaded - */ - public boolean areLeftRoomsSynced() { - return mAreLeftRoomsSynced; - } - - /** - * @return true if the left rooms are retrieving - */ - public boolean isRetrievingLeftRooms() { - return mIsRetrievingLeftRooms; - } - - /** - * Release the left rooms store - */ - public void releaseLeftRooms() { - if (mAreLeftRoomsSynced) { - mLeftRoomsStore.clear(); - mAreLeftRoomsSynced = false; - } - } - - /** - * Retrieve the historical rooms - * - * @param callback the asynchronous callback. - */ - public void retrieveLeftRooms(ApiCallback callback) { - // already loaded - if (mAreLeftRoomsSynced) { - if (null != callback) { - callback.onSuccess(null); - } - } else { - int count; - - synchronized (mLeftRoomsRefreshCallbacks) { - if (null != callback) { - mLeftRoomsRefreshCallbacks.add(callback); - } - count = mLeftRoomsRefreshCallbacks.size(); - } - - // start the request only for the first listener - if (1 == count) { - mIsRetrievingLeftRooms = true; - - Log.d(LOG_TAG, "## refreshHistoricalRoomsList() : requesting"); - - mEventsRestClient.syncFromToken(null, 0, 30000, null, LEFT_ROOMS_FILTER, new ApiCallback() { - @Override - public void onSuccess(final SyncResponse syncResponse) { - - Runnable r = new Runnable() { - @Override - public void run() { - if (null != syncResponse.rooms.leave) { - Set roomIds = syncResponse.rooms.leave.keySet(); - - // Handle first joined rooms - for (String roomId : roomIds) { - Room room = getRoom(mLeftRoomsStore, roomId, true); - - // sanity check - if (null != room) { - room.setIsLeft(true); - room.handleJoinedRoomSync(syncResponse.rooms.leave.get(roomId), true); - - RoomMember selfMember = room.getState().getMember(getUserId()); - - // keep only the left rooms (i.e not the banned / kicked ones) - if ((null == selfMember) || !TextUtils.equals(selfMember.membership, RoomMember.MEMBERSHIP_LEAVE)) { - mLeftRoomsStore.deleteRoom(roomId); - } - } - } - - Log.d(LOG_TAG, "## refreshHistoricalRoomsList() : " + mLeftRoomsStore.getRooms().size() + " left rooms"); - } - - mIsRetrievingLeftRooms = false; - mAreLeftRoomsSynced = true; - - synchronized (mLeftRoomsRefreshCallbacks) { - for (ApiCallback c : mLeftRoomsRefreshCallbacks) { - c.onSuccess(null); - } - mLeftRoomsRefreshCallbacks.clear(); - } - } - }; - - Thread t = new Thread(r); - t.setPriority(Thread.MIN_PRIORITY); - t.start(); - } - - @Override - public void onNetworkError(Exception e) { - synchronized (mLeftRoomsRefreshCallbacks) { - Log.e(LOG_TAG, "## refreshHistoricalRoomsList() : failed " + e.getMessage(), e); - - for (ApiCallback c : mLeftRoomsRefreshCallbacks) { - c.onNetworkError(e); - } - mLeftRoomsRefreshCallbacks.clear(); - } - } - - @Override - public void onMatrixError(MatrixError e) { - synchronized (mLeftRoomsRefreshCallbacks) { - Log.e(LOG_TAG, "## refreshHistoricalRoomsList() : failed " + e.getMessage()); - - for (ApiCallback c : mLeftRoomsRefreshCallbacks) { - c.onMatrixError(e); - } - mLeftRoomsRefreshCallbacks.clear(); - } - } - - @Override - public void onUnexpectedError(Exception e) { - synchronized (mLeftRoomsRefreshCallbacks) { - Log.e(LOG_TAG, "## refreshHistoricalRoomsList() : failed " + e.getMessage(), e); - - for (ApiCallback c : mLeftRoomsRefreshCallbacks) { - c.onUnexpectedError(e); - } - mLeftRoomsRefreshCallbacks.clear(); - } - } - }); - } - } - } - - /* - * Handle a 'toDevice' event - * @param event the event - */ - private void handleToDeviceEvent(Event event) { - // Decrypt event if necessary - decryptEvent(event, null); - - if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE) - && (null != event.getContent()) - && TextUtils.equals(JsonUtils.getMessageMsgType(event.getContent()), "m.bad.encrypted")) { - Log.e(LOG_TAG, "## handleToDeviceEvent() : Warning: Unable to decrypt to-device event : " + event.getContent()); - } else { - onToDeviceEvent(event); - } - } - - /** - * Decrypt an encrypted event - * - * @param event the event to decrypt - * @param timelineId the timeline identifier - * @return true if the event has been decrypted - */ - public boolean decryptEvent(Event event, String timelineId) { - if ((null != event) && TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE_ENCRYPTED)) { - if (null != getCrypto()) { - MXEventDecryptionResult result = null; - try { - result = getCrypto().decryptEvent(event, timelineId); - } catch (MXDecryptionException exception) { - event.setCryptoError(exception.getCryptoError()); - } - - if (null != result) { - event.setClearData(result); - return true; - } - } else { - event.setCryptoError(new MXCryptoError(MXCryptoError.ENCRYPTING_NOT_ENABLED_ERROR_CODE, MXCryptoError.ENCRYPTING_NOT_ENABLED_REASON, null)); - } - } - - return false; - } - - /** - * Reset replay attack data for the given timeline. - * - * @param timelineId the timeline id - */ - public void resetReplayAttackCheckInTimeline(String timelineId) { - if ((null != timelineId) && (null != mCrypto) && (null != mCrypto.getOlmDevice())) { - mCrypto.resetReplayAttackCheckInTimeline(timelineId); - } - } - - //================================================================================ - // Listeners management - //================================================================================ - - /** - * Dispatch that the store is ready. - */ - public void onStoreReady() { - mMxEventDispatcher.dispatchOnStoreReady(); - } - - public void onAccountInfoUpdate(final MyUser myUser) { - mMxEventDispatcher.dispatchOnAccountInfoUpdate(myUser); - } - - public void onPresenceUpdate(final Event event, final User user) { - mMxEventDispatcher.dispatchOnPresenceUpdate(event, user); - } - - /** - * Stored the room id of the rooms which have received some events - * which imply an unread messages counter refresh. - */ - private final Set mUpdatedRoomIdList = new HashSet<>(); - - /** - * Tell if a room Id event should be ignored - * - * @param roomId the room id - * @return true to do not dispatch the event. - */ - private boolean ignoreEvent(String roomId) { - if (mIsRetrievingLeftRooms && !TextUtils.isEmpty(roomId)) { - return null != mLeftRoomsStore.getRoom(roomId); - } else { - return false; - } - } - - public void onLiveEvent(final Event event, final RoomState roomState) { - if (ignoreEvent(event.roomId)) { - return; - } - - String type = event.getType(); - - if (!TextUtils.equals(Event.EVENT_TYPE_TYPING, type) - && !TextUtils.equals(Event.EVENT_TYPE_RECEIPT, type) - && !TextUtils.equals(Event.EVENT_TYPE_TYPING, type)) { - synchronized (mUpdatedRoomIdList) { - mUpdatedRoomIdList.add(roomState.roomId); - } - } - - mMxEventDispatcher.dispatchOnLiveEvent(event, roomState); - } - - public void onLiveEventsChunkProcessed(final String startToken, final String toToken) { - // reset the resource limit exceeded error - mResourceLimitExceededError = null; - - refreshUnreadCounters(); - - mMxEventDispatcher.dispatchOnLiveEventsChunkProcessed(startToken, toToken); - } - - public void onBingEvent(final Event event, final RoomState roomState, final BingRule bingRule) { - mMxEventDispatcher.dispatchOnBingEvent(event, roomState, bingRule, ignoreEvent(event.roomId)); - } - - /** - * Update the event state and warn the listener if there is an update. - * - * @param event the event - * @param newState the new state - */ - public void updateEventState(Event event, Event.SentState newState) { - if ((null != event) && (event.mSentState != newState)) { - event.mSentState = newState; - getStore().flushRoomEvents(event.roomId); - onEventSentStateUpdated(event); - } - } - - public void onEventSentStateUpdated(final Event event) { - mMxEventDispatcher.dispatchOnEventSentStateUpdated(event, ignoreEvent(event.roomId)); - } - - public void onEventSent(final Event event, final String prevEventId) { - mMxEventDispatcher.dispatchOnEventSent(event, prevEventId, ignoreEvent(event.roomId)); - } - - public void onBingRulesUpdate() { - mMxEventDispatcher.dispatchOnBingRulesUpdate(); - } - - /** - * Start the crypto - */ - public void startCrypto(final boolean isInitialSync) { - if ((null != getCrypto()) && !getCrypto().isStarted() && !getCrypto().isStarting()) { - getCrypto().setNetworkConnectivityReceiver(mNetworkConnectivityReceiver); - getCrypto().start(isInitialSync, new ApiCallback() { - @Override - public void onSuccess(Void info) { - onCryptoSyncComplete(); - } - - private void onError(String errorMessage) { - Log.e(LOG_TAG, "## onInitialSyncComplete() : getCrypto().start fails " + errorMessage); - } - - @Override - public void onNetworkError(Exception e) { - onError(e.getMessage()); - } - - @Override - public void onMatrixError(MatrixError e) { - onError(e.getMessage()); - } - - @Override - public void onUnexpectedError(Exception e) { - onError(e.getMessage()); - } - }); - } - } - - public void onInitialSyncComplete(String toToken) { - mInitialSyncToToken = toToken; - - refreshUnreadCounters(); - - mMxEventDispatcher.dispatchOnInitialSyncComplete(toToken); - } - - public void onSyncError(final MatrixError matrixError) { - // Store the resource limit exceeded error - if (MatrixError.RESOURCE_LIMIT_EXCEEDED.equals(matrixError.errcode)) { - mResourceLimitExceededError = matrixError; - } - - mMxEventDispatcher.dispatchOnSyncError(matrixError); - } - - public void onCryptoSyncComplete() { - mMxEventDispatcher.dispatchOnCryptoSyncComplete(); - } - - public void onNewRoom(final String roomId) { - mMxEventDispatcher.dispatchOnNewRoom(roomId, ignoreEvent(roomId)); - } - - public void onJoinRoom(final String roomId) { - mMxEventDispatcher.dispatchOnJoinRoom(roomId, ignoreEvent(roomId)); - } - - public void onRoomInternalUpdate(final String roomId) { - mMxEventDispatcher.dispatchOnRoomInternalUpdate(roomId, ignoreEvent(roomId)); - } - - public void onNotificationCountUpdate(final String roomId) { - mMxEventDispatcher.dispatchOnNotificationCountUpdate(roomId, ignoreEvent(roomId)); - } - - public void onLeaveRoom(final String roomId) { - mMxEventDispatcher.dispatchOnLeaveRoom(roomId, ignoreEvent(roomId)); - } - - public void onRoomKick(final String roomId) { - mMxEventDispatcher.dispatchOnRoomKick(roomId, ignoreEvent(roomId)); - } - - public void onReceiptEvent(final String roomId, final List senderIds) { - synchronized (mUpdatedRoomIdList) { - // refresh the unread counter at the end of the process chunk - mUpdatedRoomIdList.add(roomId); - } - - mMxEventDispatcher.dispatchOnReceiptEvent(roomId, senderIds, ignoreEvent(roomId)); - } - - public void onRoomTagEvent(final String roomId) { - mMxEventDispatcher.dispatchOnRoomTagEvent(roomId, ignoreEvent(roomId)); - } - - public void onReadMarkerEvent(final String roomId) { - mMxEventDispatcher.dispatchOnReadMarkerEvent(roomId, ignoreEvent(roomId)); - } - - public void onRoomFlush(final String roomId) { - mMxEventDispatcher.dispatchOnRoomFlush(roomId, ignoreEvent(roomId)); - } - - public void onIgnoredUsersListUpdate() { - mMxEventDispatcher.dispatchOnIgnoredUsersListUpdate(); - } - - public void onToDeviceEvent(final Event event) { - mMxEventDispatcher.dispatchOnToDeviceEvent(event, ignoreEvent(event.roomId)); - } - - public void onDirectMessageChatRoomsListUpdate() { - mMxEventDispatcher.dispatchOnDirectMessageChatRoomsListUpdate(); - } - - public void onEventDecrypted(final Event event) { - mMxEventDispatcher.dispatchOnEventDecrypted(event); - } - - public void onNewGroupInvitation(final String groupId) { - mMxEventDispatcher.dispatchOnNewGroupInvitation(groupId); - } - - public void onJoinGroup(final String groupId) { - mMxEventDispatcher.dispatchOnJoinGroup(groupId); - } - - public void onLeaveGroup(final String groupId) { - mMxEventDispatcher.dispatchOnLeaveGroup(groupId); - } - - public void onGroupProfileUpdate(final String groupId) { - mMxEventDispatcher.dispatchOnGroupProfileUpdate(groupId); - } - - public void onGroupRoomsListUpdate(final String groupId) { - mMxEventDispatcher.dispatchOnGroupRoomsListUpdate(groupId); - } - - public void onGroupUsersListUpdate(final String groupId) { - mMxEventDispatcher.dispatchOnGroupUsersListUpdate(groupId); - } - - public void onGroupInvitedUsersListUpdate(final String groupId) { - mMxEventDispatcher.dispatchOnGroupInvitedUsersListUpdate(groupId); - } - - /** - * @return the direct chat room ids list - */ - public List getDirectChatRoomIdsList() { - if (null != mLocalDirectChatRoomIdsList) return mLocalDirectChatRoomIdsList; - - IMXStore store = getStore(); - List directChatRoomIdsList = new ArrayList<>(); - - if (null == store) { - Log.e(LOG_TAG, "## getDirectChatRoomIdsList() : null store"); - return directChatRoomIdsList; - } - - Collection> listOfList = null; - - if (null != store.getDirectChatRoomsDict()) { - listOfList = store.getDirectChatRoomsDict().values(); - } - - // if the direct messages entry has been defined - if (null != listOfList) { - for (List list : listOfList) { - for (String roomId : list) { - // test if the room is defined once - if ((directChatRoomIdsList.indexOf(roomId) < 0)) { - directChatRoomIdsList.add(roomId); - } - } - } - } - - return mLocalDirectChatRoomIdsList = directChatRoomIdsList; - } - - /** - * Store and upload the provided direct chat rooms map. - * - * @param directChatRoomsMap the direct chats map - * @param callback the asynchronous callback - */ - public void setDirectChatRoomsMap(Map> directChatRoomsMap, ApiCallback callback) { - Log.d(LOG_TAG, "## setDirectChatRoomsMap()"); - IMXStore store = getStore(); - if (null != store) { - // update the store value - // do not wait the server request echo to update the store - store.setDirectChatRoomsDict(directChatRoomsMap); - } else { - Log.e(LOG_TAG, "## setDirectChatRoomsMap() : null store"); - } - mLocalDirectChatRoomIdsList = null; - // Upload the new map - mAccountDataRestClient.setAccountData(getMyUser().user_id, AccountDataRestClient.ACCOUNT_DATA_TYPE_DIRECT_MESSAGES, directChatRoomsMap, callback); - } - - /** - * This class defines a direct chat backward compliancyc structure - */ - private class RoomIdsListRetroCompat { - final String mRoomId; - final String mParticipantUserId; - - public RoomIdsListRetroCompat(String aParticipantUserId, String aRoomId) { - mParticipantUserId = aParticipantUserId; - mRoomId = aRoomId; - } - } - - /** - * Return the list of the direct chat room IDs for the user given in parameter.
- * Based on the account_data map content, the entry associated with aSearchedUserId is returned. - * - * @param aSearchedUserId user ID - * @return the list of the direct chat room Id - */ - public List getDirectChatRoomIdsList(String aSearchedUserId) { - List directChatRoomIdsList = new ArrayList<>(); - IMXStore store = getStore(); - Room room; - - Map> params; - - if (null != store.getDirectChatRoomsDict()) { - params = new HashMap<>(store.getDirectChatRoomsDict()); - if (params.containsKey(aSearchedUserId)) { - directChatRoomIdsList = new ArrayList<>(); - - for (String roomId : params.get(aSearchedUserId)) { - room = store.getRoom(roomId); - if (null != room) { // skipp empty rooms - directChatRoomIdsList.add(roomId); - } - } - } else { - Log.w(LOG_TAG, "## getDirectChatRoomIdsList(): UserId " + aSearchedUserId + " has no entry in account_data"); - } - } else { - Log.w(LOG_TAG, "## getDirectChatRoomIdsList(): failure - getDirectChatRoomsDict()=null"); - } - - return directChatRoomIdsList; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/MXPatterns.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/MXPatterns.java deleted file mode 100644 index 4dbeb502..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/MXPatterns.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy; - -import android.support.annotation.Nullable; - -import java.util.Arrays; -import java.util.List; -import java.util.regex.Pattern; - -/** - * This class contains pattern to match the different Matrix ids - */ -public class MXPatterns { - - private MXPatterns() { - // Cannot be instantiated - } - - // Note: TLD is not mandatory (localhost, IP address...) - private static final String DOMAIN_REGEX = ":[A-Z0-9.-]+(:[0-9]{2,5})?"; - - // regex pattern to find matrix user ids in a string. - // See https://matrix.org/speculator/spec/HEAD/appendices.html#historical-user-ids - private static final String MATRIX_USER_IDENTIFIER_REGEX = "@[A-Z0-9\\x21-\\x39\\x3B-\\x7F]+" + DOMAIN_REGEX; - public static final Pattern PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER = Pattern.compile(MATRIX_USER_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); - - // regex pattern to find room ids in a string. - private static final String MATRIX_ROOM_IDENTIFIER_REGEX = "![A-Z0-9]+" + DOMAIN_REGEX; - public static final Pattern PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER = Pattern.compile(MATRIX_ROOM_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); - - // regex pattern to find room aliases in a string. - private static final String MATRIX_ROOM_ALIAS_REGEX = "#[A-Z0-9._%#@=+-]+" + DOMAIN_REGEX; - public static final Pattern PATTERN_CONTAIN_MATRIX_ALIAS = Pattern.compile(MATRIX_ROOM_ALIAS_REGEX, Pattern.CASE_INSENSITIVE); - - // regex pattern to find message ids in a string. - private static final String MATRIX_EVENT_IDENTIFIER_REGEX = "\\$[A-Z0-9]+" + DOMAIN_REGEX; - public static final Pattern PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER = Pattern.compile(MATRIX_EVENT_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); - - // regex pattern to find group ids in a string. - private static final String MATRIX_GROUP_IDENTIFIER_REGEX = "\\+[A-Z0-9=_\\-./]+" + DOMAIN_REGEX; - public static final Pattern PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER = Pattern.compile(MATRIX_GROUP_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); - - // regex pattern to find permalink with message id. - // Android does not support in URL so extract it. - private static final String PERMALINK_BASE_REGEX = "https://matrix\\.to/#/"; - private static final String APP_BASE_REGEX = "https://[A-Z0-9.-]+\\.[A-Z]{2,}/[A-Z]{3,}/#/room/"; - private static final String SEP_REGEX = "/"; - - private static final String LINK_TO_ROOM_ID_REGEXP = PERMALINK_BASE_REGEX + MATRIX_ROOM_IDENTIFIER_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX; - public static final Pattern PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ID = Pattern.compile(LINK_TO_ROOM_ID_REGEXP, Pattern.CASE_INSENSITIVE); - - private static final String LINK_TO_ROOM_ALIAS_REGEXP = PERMALINK_BASE_REGEX + MATRIX_ROOM_ALIAS_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX; - public static final Pattern PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ALIAS = Pattern.compile(LINK_TO_ROOM_ALIAS_REGEXP, Pattern.CASE_INSENSITIVE); - - private static final String LINK_TO_APP_ROOM_ID_REGEXP = APP_BASE_REGEX + MATRIX_ROOM_IDENTIFIER_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX; - public static final Pattern PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ID = Pattern.compile(LINK_TO_APP_ROOM_ID_REGEXP, Pattern.CASE_INSENSITIVE); - - private static final String LINK_TO_APP_ROOM_ALIAS_REGEXP = APP_BASE_REGEX + MATRIX_ROOM_ALIAS_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX; - public static final Pattern PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ALIAS = Pattern.compile(LINK_TO_APP_ROOM_ALIAS_REGEXP, Pattern.CASE_INSENSITIVE); - - // list of patterns to find some matrix item. - public static final List MATRIX_PATTERNS = Arrays.asList( - MXPatterns.PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ID, - MXPatterns.PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ALIAS, - MXPatterns.PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ID, - MXPatterns.PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ALIAS, - MXPatterns.PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER, - MXPatterns.PATTERN_CONTAIN_MATRIX_ALIAS, - MXPatterns.PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER, - MXPatterns.PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER, - MXPatterns.PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER - ); - - /** - * Tells if a string is a valid user Id. - * - * @param str the string to test - * @return true if the string is a valid user id - */ - public static boolean isUserId(@Nullable final String str) { - return str != null && PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER.matcher(str).matches(); - } - - /** - * Tells if a string is a valid room id. - * - * @param str the string to test - * @return true if the string is a valid room Id - */ - public static boolean isRoomId(@Nullable final String str) { - return str != null && PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER.matcher(str).matches(); - } - - /** - * Tells if a string is a valid room alias. - * - * @param str the string to test - * @return true if the string is a valid room alias. - */ - public static boolean isRoomAlias(@Nullable final String str) { - return str != null && PATTERN_CONTAIN_MATRIX_ALIAS.matcher(str).matches(); - } - - /** - * Tells if a string is a valid event id. - * - * @param str the string to test - * @return true if the string is a valid event id. - */ - public static boolean isEventId(@Nullable final String str) { - return str != null && PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER.matcher(str).matches(); - } - - /** - * Tells if a string is a valid group id. - * - * @param str the string to test - * @return true if the string is a valid group id. - */ - public static boolean isGroupId(@Nullable final String str) { - return str != null && PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER.matcher(str).matches(); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/MXSession.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/MXSession.java deleted file mode 100644 index 186174f1..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/MXSession.java +++ /dev/null @@ -1,2549 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy; - -import android.content.Context; -import android.content.IntentFilter; -import android.net.ConnectivityManager; -import android.net.Uri; -import android.os.AsyncTask; -import android.os.Handler; -import android.os.Looper; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.text.TextUtils; - -import com.google.gson.JsonObject; - -import org.matrix.olm.OlmManager; - -import java.io.File; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig; -import im.vector.matrix.android.api.auth.data.Credentials; -import im.vector.matrix.android.api.auth.data.SessionParams; -import im.vector.matrix.android.internal.legacy.call.MXCallsManager; -import im.vector.matrix.android.internal.legacy.crypto.MXCrypto; -import im.vector.matrix.android.internal.legacy.crypto.MXCryptoConfig; -import im.vector.matrix.android.internal.legacy.data.DataRetriever; -import im.vector.matrix.android.internal.legacy.data.MyUser; -import im.vector.matrix.android.internal.legacy.data.Room; -import im.vector.matrix.android.internal.legacy.data.RoomSummary; -import im.vector.matrix.android.internal.legacy.data.RoomTag; -import im.vector.matrix.android.internal.legacy.data.comparator.RoomComparatorWithTag; -import im.vector.matrix.android.internal.legacy.data.cryptostore.IMXCryptoStore; -import im.vector.matrix.android.internal.legacy.data.cryptostore.MXFileCryptoStore; -import im.vector.matrix.android.internal.legacy.data.metrics.MetricsListener; -import im.vector.matrix.android.internal.legacy.data.store.IMXStore; -import im.vector.matrix.android.internal.legacy.data.store.MXStoreListener; -import im.vector.matrix.android.internal.legacy.db.MXLatestChatMessageCache; -import im.vector.matrix.android.internal.legacy.db.MXMediasCache; -import im.vector.matrix.android.internal.legacy.groups.GroupsManager; -import im.vector.matrix.android.internal.legacy.network.NetworkConnectivityReceiver; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiFailureCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.SimpleApiCallback; -import im.vector.matrix.android.internal.legacy.rest.client.AccountDataRestClient; -import im.vector.matrix.android.internal.legacy.rest.client.CallRestClient; -import im.vector.matrix.android.internal.legacy.rest.client.CryptoRestClient; -import im.vector.matrix.android.internal.legacy.rest.client.EventsRestClient; -import im.vector.matrix.android.internal.legacy.rest.client.FilterRestClient; -import im.vector.matrix.android.internal.legacy.rest.client.GroupsRestClient; -import im.vector.matrix.android.internal.legacy.rest.client.LoginRestClient; -import im.vector.matrix.android.internal.legacy.rest.client.MediaScanRestClient; -import im.vector.matrix.android.internal.legacy.rest.client.PresenceRestClient; -import im.vector.matrix.android.internal.legacy.rest.client.ProfileRestClient; -import im.vector.matrix.android.internal.legacy.rest.client.PushRulesRestClient; -import im.vector.matrix.android.internal.legacy.rest.client.PushersRestClient; -import im.vector.matrix.android.internal.legacy.rest.client.RoomsRestClient; -import im.vector.matrix.android.internal.legacy.rest.client.ThirdPidRestClient; -import im.vector.matrix.android.internal.legacy.rest.model.CreateRoomParams; -import im.vector.matrix.android.internal.legacy.rest.model.CreateRoomResponse; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.rest.model.ReceiptData; -import im.vector.matrix.android.internal.legacy.rest.model.RoomDirectoryVisibility; -import im.vector.matrix.android.internal.legacy.rest.model.RoomMember; -import im.vector.matrix.android.internal.legacy.rest.model.User; -import im.vector.matrix.android.internal.legacy.rest.model.Versions; -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.BingRule; -import im.vector.matrix.android.internal.legacy.rest.model.filter.FilterBody; -import im.vector.matrix.android.internal.legacy.rest.model.filter.FilterResponse; -import im.vector.matrix.android.internal.legacy.rest.model.login.LoginFlow; -import im.vector.matrix.android.internal.legacy.rest.model.login.RegistrationFlowResponse; -import im.vector.matrix.android.internal.legacy.rest.model.message.MediaMessage; -import im.vector.matrix.android.internal.legacy.rest.model.message.Message; -import im.vector.matrix.android.internal.legacy.rest.model.pid.DeleteDeviceAuth; -import im.vector.matrix.android.internal.legacy.rest.model.pid.DeleteDeviceParams; -import im.vector.matrix.android.internal.legacy.rest.model.search.SearchResponse; -import im.vector.matrix.android.internal.legacy.rest.model.search.SearchUsersResponse; -import im.vector.matrix.android.internal.legacy.rest.model.sync.DevicesListResponse; -import im.vector.matrix.android.internal.legacy.rest.model.sync.RoomResponse; -import im.vector.matrix.android.internal.legacy.sync.DefaultEventsThreadListener; -import im.vector.matrix.android.internal.legacy.sync.EventsThread; -import im.vector.matrix.android.internal.legacy.sync.EventsThreadListener; -import im.vector.matrix.android.internal.legacy.util.BingRulesManager; -import im.vector.matrix.android.internal.legacy.util.ContentManager; -import im.vector.matrix.android.internal.legacy.util.ContentUtils; -import im.vector.matrix.android.internal.legacy.util.FilterUtil; -import im.vector.matrix.android.internal.legacy.util.JsonUtils; -import im.vector.matrix.android.internal.legacy.util.Log; -import im.vector.matrix.android.internal.legacy.util.UnsentEventsManager; -import im.vector.matrix.android.internal.legacy.util.VersionsUtil; - -/** - * Class that represents one user's session with a particular home server. - * There can potentially be multiple sessions for handling multiple accounts. - */ -public class MXSession { - private static final String LOG_TAG = MXSession.class.getSimpleName(); - - private DataRetriever mDataRetriever; - private MXDataHandler mDataHandler; - private EventsThread mEventsThread; - private final Credentials mCredentials; - - // Api clients - private EventsRestClient mEventsRestClient; - private ProfileRestClient mProfileRestClient; - private PresenceRestClient mPresenceRestClient; - private RoomsRestClient mRoomsRestClient; - private final PushRulesRestClient mPushRulesRestClient; - private PushersRestClient mPushersRestClient; - private final ThirdPidRestClient mThirdPidRestClient; - private final CallRestClient mCallRestClient; - private final AccountDataRestClient mAccountDataRestClient; - private final CryptoRestClient mCryptoRestClient; - private final LoginRestClient mLoginRestClient; - private final GroupsRestClient mGroupsRestClient; - private final MediaScanRestClient mMediaScanRestClient; - private final FilterRestClient mFilterRestClient; - - private ApiFailureCallback mFailureCallback; - - private ContentManager mContentManager; - - public MXCallsManager mCallsManager; - - private MetricsListener mMetricsListener; - - private Context mAppContent; - private NetworkConnectivityReceiver mNetworkConnectivityReceiver; - private UnsentEventsManager mUnsentEventsManager; - - private MXLatestChatMessageCache mLatestChatMessageCache; - private MXMediasCache mMediasCache; - - private BingRulesManager mBingRulesManager = null; - - private boolean mIsAliveSession = true; - - // online status - private boolean mIsOnline = false; - private int mSyncTimeout = 0; - private int mSyncDelay = 0; - - private final HomeServerConnectionConfig mHsConfig; - - // True if file encryption is enabled - private boolean mEnableFileEncryption; - - // the application is launched from a notification - // so, mEventsThread.start might be not ready - private boolean mIsBgCatchupPending = false; - - private FilterBody mCurrentFilter = new FilterBody(); - - // tell if the data save mode is enabled - private boolean mUseDataSaveMode; - - // the groups manager - private GroupsManager mGroupsManager; - - // load the crypto libs. - public static OlmManager mOlmManager = new OlmManager(); - - /** - * Create a basic session for direct API calls. - * - * @param sessionParams the session connection data - */ - private MXSession(final SessionParams sessionParams) { - mCredentials = sessionParams.getCredentials(); - mHsConfig = sessionParams.getHomeServerConnectionConfig(); - - mEventsRestClient = new EventsRestClient(sessionParams); - mProfileRestClient = new ProfileRestClient(sessionParams); - mPresenceRestClient = new PresenceRestClient(sessionParams); - mRoomsRestClient = new RoomsRestClient(sessionParams); - mPushRulesRestClient = new PushRulesRestClient(sessionParams); - mPushersRestClient = new PushersRestClient(sessionParams); - mThirdPidRestClient = new ThirdPidRestClient(sessionParams); - mCallRestClient = new CallRestClient(sessionParams); - mAccountDataRestClient = new AccountDataRestClient(sessionParams); - mCryptoRestClient = new CryptoRestClient(sessionParams); - mLoginRestClient = new LoginRestClient(sessionParams); - mGroupsRestClient = new GroupsRestClient(sessionParams); - mMediaScanRestClient = new MediaScanRestClient(sessionParams); - mFilterRestClient = new FilterRestClient(sessionParams); - } - - /** - * Create a user session with a data handler. - * Private, please use the MxSession.Builder now - * - * @param sessionParams the session connection data - * @param dataHandler the data handler - * @param appContext the application context - */ - private MXSession(final SessionParams sessionParams, MXDataHandler dataHandler, Context appContext) { - this(sessionParams); - mDataHandler = dataHandler; - - mDataHandler.getStore().addMXStoreListener(new MXStoreListener() { - @Override - public void onStoreReady(String accountId) { - Log.d(LOG_TAG, "## onStoreReady()"); - getDataHandler().onStoreReady(); - } - - @Override - public void onStoreCorrupted(String accountId, String description) { - Log.d(LOG_TAG, "## onStoreCorrupted() : token " + getDataHandler().getStore().getEventStreamToken()); - - // nothing was saved - if (null == getDataHandler().getStore().getEventStreamToken()) { - getDataHandler().onStoreReady(); - } - } - - @Override - public void postProcess(String accountId) { - getDataHandler().checkPermanentStorageData(); - - // test if the crypto instance has already been created - if (null == mCrypto) { - MXFileCryptoStore store = new MXFileCryptoStore(mEnableFileEncryption); - store.initWithCredentials(mAppContent, mCredentials); - - if (store.hasData() || mEnableCryptoWhenStartingMXSession) { - Log.d(LOG_TAG, "## postProcess() : create the crypto instance for session " + this); - checkCrypto(); - } else { - Log.e(LOG_TAG, "## postProcess() : no crypto data"); - } - } else { - Log.e(LOG_TAG, "## postProcess() : mCrypto is already created"); - } - } - - @Override - public void onReadReceiptsLoaded(final String roomId) { - final List receipts = mDataHandler.getStore().getEventReceipts(roomId, null, false, false); - final List senders = new ArrayList<>(); - - for (ReceiptData receipt : receipts) { - senders.add(receipt.userId); - } - - mDataHandler.onReceiptEvent(roomId, senders); - } - }); - - // Initialize a data retriever with rest clients - mDataRetriever = new DataRetriever(); - mDataRetriever.setRoomsRestClient(mRoomsRestClient); - mDataHandler.setDataRetriever(mDataRetriever); - mDataHandler.setProfileRestClient(mProfileRestClient); - mDataHandler.setPresenceRestClient(mPresenceRestClient); - mDataHandler.setThirdPidRestClient(mThirdPidRestClient); - mDataHandler.setRoomsRestClient(mRoomsRestClient); - mDataHandler.setEventsRestClient(mEventsRestClient); - mDataHandler.setAccountDataRestClient(mAccountDataRestClient); - - // application context - mAppContent = appContext; - - mNetworkConnectivityReceiver = new NetworkConnectivityReceiver(); - mNetworkConnectivityReceiver.checkNetworkConnection(appContext); - mDataHandler.setNetworkConnectivityReceiver(mNetworkConnectivityReceiver); - mAppContent.registerReceiver(mNetworkConnectivityReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); - - mBingRulesManager = new BingRulesManager(this, mNetworkConnectivityReceiver); - mDataHandler.setPushRulesManager(mBingRulesManager); - - mUnsentEventsManager = new UnsentEventsManager(mNetworkConnectivityReceiver, mDataHandler); - - mContentManager = new ContentManager(mHsConfig, mCredentials, mUnsentEventsManager); - - // - mCallsManager = new MXCallsManager(this, mAppContent); - mDataHandler.setCallsManager(mCallsManager); - - // the rest client - mEventsRestClient.setUnsentEventsManager(mUnsentEventsManager); - - mProfileRestClient.setUnsentEventsManager(mUnsentEventsManager); - mPresenceRestClient.setUnsentEventsManager(mUnsentEventsManager); - mRoomsRestClient.setUnsentEventsManager(mUnsentEventsManager); - mPushRulesRestClient.setUnsentEventsManager(mUnsentEventsManager); - mThirdPidRestClient.setUnsentEventsManager(mUnsentEventsManager); - mCallRestClient.setUnsentEventsManager(mUnsentEventsManager); - mAccountDataRestClient.setUnsentEventsManager(mUnsentEventsManager); - mCryptoRestClient.setUnsentEventsManager(mUnsentEventsManager); - mLoginRestClient.setUnsentEventsManager(mUnsentEventsManager); - mGroupsRestClient.setUnsentEventsManager(mUnsentEventsManager); - - // return the default cache manager - mLatestChatMessageCache = new MXLatestChatMessageCache(mCredentials.getUserId()); - mMediasCache = new MXMediasCache(mContentManager, mNetworkConnectivityReceiver, mCredentials.getUserId(), appContext); - mDataHandler.setMediasCache(mMediasCache); - - mMediaScanRestClient.setMxStore(mDataHandler.getStore()); - mMediasCache.setMediaScanRestClient(mMediaScanRestClient); - - mGroupsManager = new GroupsManager(mDataHandler, mGroupsRestClient); - mDataHandler.setGroupsManager(mGroupsManager); - } - - private void checkIfAlive() { - synchronized (this) { - if (!mIsAliveSession) { - // Create an Exception to log the stack trace - Log.e(LOG_TAG, "Use of a released session", new Exception("Use of a released session")); - - //throw new AssertionError("Should not used a cleared mxsession "); - } - } - } - - /** - * Init the user-agent used by the REST requests. - * - * @param context the application context - */ - public static void initUserAgent(Context context) { - RestClient.initUserAgent(context); - } - - /** - * Provides the crypto lib version. - * - * @param context the context - * @param longFormat true to have a long version (with date and time) - * @return the crypto lib version - */ - public String getCryptoVersion(Context context, boolean longFormat) { - String version = ""; - - if (null != mOlmManager) { - version = longFormat ? mOlmManager.getDetailedVersion(context) : mOlmManager.getVersion(); - } - - return version; - } - - /** - * Get the data handler. - * - * @return the data handler. - */ - public MXDataHandler getDataHandler() { - checkIfAlive(); - return mDataHandler; - } - - /** - * Get the user getCredentials. - * - * @return the getCredentials - */ - public Credentials getCredentials() { - checkIfAlive(); - return mCredentials; - } - - /** - * Get the API client for requests to the events API. - * - * @return the events API client - */ - public EventsRestClient getEventsApiClient() { - checkIfAlive(); - return mEventsRestClient; - } - - /** - * Get the API client for requests to the profile API. - * - * @return the profile API client - */ - public ProfileRestClient getProfileApiClient() { - checkIfAlive(); - return mProfileRestClient; - } - - /** - * Get the API client for requests to the presence API. - * - * @return the presence API client - */ - public PresenceRestClient getPresenceApiClient() { - checkIfAlive(); - return mPresenceRestClient; - } - - public FilterRestClient getFilterRestClient() { - checkIfAlive(); - return mFilterRestClient; - } - - /** - * Refresh the presence info of a dedicated user. - * - * @param userId the user userID. - * @param callback the callback. - */ - public void refreshUserPresence(final String userId, final ApiCallback callback) { - mPresenceRestClient.getPresence(userId, new SimpleApiCallback(callback) { - @Override - public void onSuccess(User user) { - User currentUser = mDataHandler.getStore().getUser(userId); - - if (null != currentUser) { - currentUser.presence = user.presence; - currentUser.currently_active = user.currently_active; - currentUser.lastActiveAgo = user.lastActiveAgo; - } else { - currentUser = user; - } - - currentUser.setLatestPresenceTs(System.currentTimeMillis()); - mDataHandler.getStore().storeUser(currentUser); - if (null != callback) { - callback.onSuccess(null); - } - } - }); - } - - /** - * Get the API client for requests to the bing rules API. - * - * @return the bing rules API client - */ - public PushRulesRestClient getBingRulesApiClient() { - checkIfAlive(); - return mPushRulesRestClient; - } - - public ThirdPidRestClient getThirdPidRestClient() { - checkIfAlive(); - return mThirdPidRestClient; - } - - public CallRestClient getCallRestClient() { - checkIfAlive(); - return mCallRestClient; - } - - public PushersRestClient getPushersRestClient() { - checkIfAlive(); - return mPushersRestClient; - } - - public CryptoRestClient getCryptoRestClient() { - checkIfAlive(); - return mCryptoRestClient; - } - - public HomeServerConnectionConfig getHomeServerConfig() { - checkIfAlive(); - return mHsConfig; - } - - /** - * Get the API client for requests to the rooms API. - * - * @return the rooms API client - */ - public RoomsRestClient getRoomsApiClient() { - checkIfAlive(); - return mRoomsRestClient; - } - - public MediaScanRestClient getMediaScanRestClient() { - checkIfAlive(); - return mMediaScanRestClient; - } - - protected void setEventsApiClient(EventsRestClient eventsRestClient) { - checkIfAlive(); - mEventsRestClient = eventsRestClient; - } - - protected void setProfileApiClient(ProfileRestClient profileRestClient) { - checkIfAlive(); - mProfileRestClient = profileRestClient; - } - - protected void setPresenceApiClient(PresenceRestClient presenceRestClient) { - checkIfAlive(); - mPresenceRestClient = presenceRestClient; - } - - protected void setRoomsApiClient(RoomsRestClient roomsRestClient) { - checkIfAlive(); - mRoomsRestClient = roomsRestClient; - } - - public MXLatestChatMessageCache getLatestChatMessageCache() { - checkIfAlive(); - return mLatestChatMessageCache; - } - - public MXMediasCache getMediasCache() { - checkIfAlive(); - return mMediasCache; - } - - /** - * Provides the application caches size. - * - * @param context the context - * @param callback the asynchronous callback - */ - public static void getApplicationSizeCaches(final Context context, final ApiCallback callback) { - AsyncTask task = new AsyncTask() { - @Override - protected Long doInBackground(Void... params) { - return ContentUtils.getDirectorySize(context, context.getApplicationContext().getFilesDir().getParentFile(), 5); - } - - @Override - protected void onPostExecute(Long result) { - Log.d(LOG_TAG, "## getCacheSize() : " + result); - if (null != callback) { - callback.onSuccess(result); - } - } - }; - try { - task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } catch (final Exception e) { - Log.e(LOG_TAG, "## getApplicationSizeCaches() : failed " + e.getMessage(), e); - task.cancel(true); - - (new android.os.Handler(Looper.getMainLooper())).post(new Runnable() { - @Override - public void run() { - if (null != callback) { - callback.onUnexpectedError(e); - } - } - }); - - } - } - - /** - * Clear the application cache - */ - private void clearApplicationCaches(Context context) { - mDataHandler.clear(); - - // network event will not be listened anymore - try { - mAppContent.unregisterReceiver(mNetworkConnectivityReceiver); - } catch (Exception e) { - Log.e(LOG_TAG, "## clearApplicationCaches() : unregisterReceiver failed " + e.getMessage(), e); - } - mNetworkConnectivityReceiver.removeListeners(); - - // auto resent messages will not be resent - mUnsentEventsManager.clear(); - - mLatestChatMessageCache.clearCache(context); - mMediasCache.clear(); - - if (null != mCrypto) { - mCrypto.close(); - } - } - - /** - * Clear the session data synchronously. - * - * @param context the context - */ - public void clear(final Context context) { - clear(context, null); - } - - /** - * Clear the session data. - * if the callback is null, the clear is synchronous. - * - * @param context the context - * @param callback the asynchronous callback - */ - public void clear(final Context context, final ApiCallback callback) { - synchronized (this) { - if (!mIsAliveSession) { - Log.e(LOG_TAG, "## clear() was already called"); - return; - } - - mIsAliveSession = false; - } - - // stop events stream - stopEventStream(); - - if (null == callback) { - clearApplicationCaches(context); - } else { - // clear the caches in a background thread to avoid blocking the UI thread - AsyncTask task = new AsyncTask() { - @Override - protected Void doInBackground(Void... params) { - clearApplicationCaches(context); - return null; - } - - @Override - protected void onPostExecute(Void args) { - if (null != callback) { - callback.onSuccess(null); - } - } - }; - - try { - task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } catch (final Exception e) { - Log.e(LOG_TAG, "## clear() failed " + e.getMessage(), e); - task.cancel(true); - - (new android.os.Handler(Looper.getMainLooper())).post(new Runnable() { - @Override - public void run() { - if (null != callback) { - callback.onUnexpectedError(e); - } - } - }); - } - } - } - - /** - * Remove the medias older than the provided timestamp. - * - * @param context the context - * @param timestamp the timestamp (in seconds) - */ - public void removeMediasBefore(final Context context, final long timestamp) { - // list the files to keep even if they are older than the provided timestamp - // because their upload failed - final Set filesToKeep = new HashSet<>(); - IMXStore store = getDataHandler().getStore(); - - Collection rooms = store.getRooms(); - - for (Room room : rooms) { - Collection events = store.getRoomMessages(room.getRoomId()); - if (null != events) { - for (Event event : events) { - try { - Message message = null; - - if (TextUtils.equals(Event.EVENT_TYPE_MESSAGE, event.getType())) { - message = JsonUtils.toMessage(event.getContent()); - } else if (TextUtils.equals(Event.EVENT_TYPE_STICKER, event.getType())) { - message = JsonUtils.toStickerMessage(event.getContent()); - } - - if (null != message && message instanceof MediaMessage) { - MediaMessage mediaMessage = (MediaMessage) message; - - if (mediaMessage.isThumbnailLocalContent()) { - filesToKeep.add(Uri.parse(mediaMessage.getThumbnailUrl()).getPath()); - } - - if (mediaMessage.isLocalContent()) { - filesToKeep.add(Uri.parse(mediaMessage.getUrl()).getPath()); - } - } - } catch (Exception e) { - Log.e(LOG_TAG, "## removeMediasBefore() : failed " + e.getMessage(), e); - } - } - } - } - - AsyncTask task = new AsyncTask() { - @Override - protected Void doInBackground(Void... params) { - long length = getMediasCache().removeMediasBefore(timestamp, filesToKeep); - - // delete also the log files - // they might be large - File logsDir = Log.getLogDirectory(); - - if (null != logsDir) { - File[] logFiles = logsDir.listFiles(); - - if (null != logFiles) { - for (File file : logFiles) { - if (ContentUtils.getLastAccessTime(file) < timestamp) { - length += file.length(); - file.delete(); - } - } - } - } - - if (0 != length) { - Log.d(LOG_TAG, "## removeMediasBefore() : save " + android.text.format.Formatter.formatFileSize(context, length)); - } else { - Log.d(LOG_TAG, "## removeMediasBefore() : useless"); - } - - return null; - } - }; - try { - task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } catch (Exception e) { - Log.e(LOG_TAG, "## removeMediasBefore() : failed " + e.getMessage(), e); - task.cancel(true); - } - } - - /** - * @return true if the session is active i.e. has not been cleared after a logout. - */ - public boolean isAlive() { - synchronized (this) { - return mIsAliveSession; - } - } - - /** - * Get the content manager (for uploading and downloading content) associated with the session. - * - * @return the content manager - */ - public ContentManager getContentManager() { - checkIfAlive(); - return mContentManager; - } - - /** - * Get the session's current user. The MyUser object provides methods for updating user properties which are not possible for other users. - * - * @return the session's MyUser object - */ - public MyUser getMyUser() { - checkIfAlive(); - - return mDataHandler.getMyUser(); - } - - - /** - * Get the session's current userid. - * - * @return the session's MyUser id - */ - public String getMyUserId() { - checkIfAlive(); - - if (null != mDataHandler.getMyUser()) { - return mDataHandler.getMyUser().user_id; - } - return null; - } - - /** - * Start the event stream (events thread that listens for events) with an event listener. - * - * @param anEventsListener the event listener or null if using a DataHandler - * @param networkConnectivityReceiver the network connectivity listener. - * @param initialToken the initial sync token (null to start from scratch) - */ - public void startEventStream(final EventsThreadListener anEventsListener, - final NetworkConnectivityReceiver networkConnectivityReceiver, - final String initialToken) { - checkIfAlive(); - - // reported by a rageshake issue - // startEventStream might be called several times - // when the service is killed and automatically restarted. - // It might be restarted by itself and by android at the same time. - synchronized (LOG_TAG) { - if (mEventsThread != null) { - if (!mEventsThread.isAlive()) { - mEventsThread = null; - Log.e(LOG_TAG, "startEventStream() : create a new EventsThread"); - } else { - // https://github.com/vector-im/riot-android/issues/1331 - mEventsThread.cancelKill(); - Log.e(LOG_TAG, "Ignoring startEventStream() : Thread already created."); - return; - } - } - - if (mDataHandler == null) { - Log.e(LOG_TAG, "Error starting the event stream: No data handler is defined"); - return; - } - - Log.d(LOG_TAG, "startEventStream : create the event stream"); - - final EventsThreadListener fEventsListener = (null == anEventsListener) ? new DefaultEventsThreadListener(mDataHandler) : anEventsListener; - - mEventsThread = new EventsThread(mAppContent, mEventsRestClient, fEventsListener, initialToken); - setSyncFilter(mCurrentFilter); - mEventsThread.setMetricsListener(mMetricsListener); - mEventsThread.setNetworkConnectivityReceiver(networkConnectivityReceiver); - mEventsThread.setIsOnline(mIsOnline); - mEventsThread.setServerLongPollTimeout(mSyncTimeout); - mEventsThread.setSyncDelay(mSyncDelay); - - if (mFailureCallback != null) { - mEventsThread.setFailureCallback(mFailureCallback); - } - - if (mCredentials.getAccessToken() != null && !mEventsThread.isAlive()) { - // GA issue - try { - mEventsThread.start(); - } catch (Exception e) { - Log.e(LOG_TAG, "## startEventStream() : mEventsThread.start failed " + e.getMessage(), e); - } - - if (mIsBgCatchupPending) { - Log.d(LOG_TAG, "startEventStream : start a catchup"); - mIsBgCatchupPending = false; - // catchup retrieve any available messages before stop the sync - mEventsThread.catchup(); - } - } - } - } - - /** - * Update the online status - * - * @param isOnline true if the client must be seen as online - */ - public void setIsOnline(boolean isOnline) { - if (isOnline != mIsOnline) { - mIsOnline = isOnline; - - if (null != mEventsThread) { - mEventsThread.setIsOnline(isOnline); - } - } - } - - /** - * @return true if the client is seen as "online" - */ - public boolean isOnline() { - return mIsOnline; - } - - /** - * Update the heartbeat request timeout. - * - * @param ms the delay in ms - */ - public void setSyncTimeout(int ms) { - mSyncTimeout = ms; - if (null != mEventsThread) { - mEventsThread.setServerLongPollTimeout(ms); - } - } - - /** - * @return the heartbeat request timeout - */ - public int getSyncTimeout() { - return mSyncTimeout; - } - - /** - * Set a delay between two sync requests. - * - * @param ms the delay in ms - */ - public void setSyncDelay(int ms) { - mSyncDelay = ms; - if (null != mEventsThread) { - mEventsThread.setSyncDelay(ms); - } - } - - /** - * @return the delay between two sync requests. - */ - public int getSyncDelay() { - return mSyncDelay; - } - - /** - * Update the data save mode. - * - * @param enabled true to enable the data save mode - */ - public void setUseDataSaveMode(boolean enabled) { - mUseDataSaveMode = enabled; - - if (mEventsThread != null) { - setSyncFilter(mCurrentFilter); - } - } - - /** - * Allows setting the filter used by the EventsThread - * - * @param filter the content of the filter param on sync requests - */ - public synchronized void setSyncFilter(FilterBody filter) { - Log.d(LOG_TAG, "setSyncFilter ## " + filter); - mCurrentFilter = filter; - - // Enable Data save mode and/or LazyLoading - FilterUtil.enableDataSaveMode(mCurrentFilter, mUseDataSaveMode); - FilterUtil.enableLazyLoading(mCurrentFilter, mDataHandler.isLazyLoadingEnabled()); - - convertFilterToFilterId(); - } - - /** - * Convert a filter to a filterId - * Either it is already known to the server, or send the filter to the server to get a filterId - */ - private void convertFilterToFilterId() { - // Ensure mCurrentFilter has not been updated in the same time - final String wantedJsonFilter = mCurrentFilter.toJSONString(); - - // Check if the current filter is known by the server, to directly use the filterId - String filterId = getDataHandler().getStore().getFilters().get(wantedJsonFilter); - - if (TextUtils.isEmpty(filterId)) { - // enable the filter in JSON representation so do not block sync until the filter response is there - mEventsThread.setFilterOrFilterId(wantedJsonFilter); - - // Send the filter to the server - mFilterRestClient.uploadFilter(getMyUserId(), mCurrentFilter, new SimpleApiCallback() { - @Override - public void onSuccess(FilterResponse filter) { - // Store the couple filter/filterId - getDataHandler().getStore().addFilter(wantedJsonFilter, filter.filterId); - - // Ensure the filter is still corresponding to the current filter - if (TextUtils.equals(wantedJsonFilter, mCurrentFilter.toJSONString())) { - // Tell the event thread to use the id now - mEventsThread.setFilterOrFilterId(filter.filterId); - } - } - }); - } else { - // Tell the event thread to use the id now - mEventsThread.setFilterOrFilterId(filterId); - } - } - - /** - * Refresh the network connection information. - * On android version older than 6.0, the doze mode might have killed the network connection. - */ - public void refreshNetworkConnection() { - if (null != mNetworkConnectivityReceiver) { - // mNetworkConnectivityReceiver is a broadcastReceiver - // but some users reported that the network updates were not dispatched - mNetworkConnectivityReceiver.checkNetworkConnection(mAppContent); - } - } - - /** - * Shorthand for {@link #startEventStream(EventsThreadListener, NetworkConnectivityReceiver, String)} with no eventListener - * using a DataHandler and no specific failure callback. - * - * @param initialToken the initial sync token (null to sync from scratch). - */ - public void startEventStream(String initialToken) { - checkIfAlive(); - startEventStream(null, mNetworkConnectivityReceiver, initialToken); - } - - /** - * Gracefully stop the event stream. - */ - public void stopEventStream() { - if (null != mCallsManager) { - mCallsManager.stopTurnServerRefresh(); - } - - if (null != mEventsThread) { - Log.d(LOG_TAG, "stopEventStream"); - - mEventsThread.kill(); - mEventsThread = null; - } else { - Log.e(LOG_TAG, "stopEventStream : mEventsThread is already null"); - } - } - - /** - * Pause the event stream - */ - public void pauseEventStream() { - checkIfAlive(); - - if (null != mCallsManager) { - mCallsManager.pauseTurnServerRefresh(); - } - - if (null != mEventsThread) { - Log.d(LOG_TAG, "pauseEventStream"); - mEventsThread.pause(); - } else { - Log.e(LOG_TAG, "pauseEventStream : mEventsThread is null"); - } - - if (null != getMediasCache()) { - getMediasCache().clearTmpDecryptedMediaCache(); - } - - if (null != mGroupsManager) { - mGroupsManager.onSessionPaused(); - } - } - - /** - * @return the current sync token - */ - public String getCurrentSyncToken() { - return (null != mEventsThread) ? mEventsThread.getCurrentSyncToken() : null; - } - - /** - * Resume the event stream - */ - public void resumeEventStream() { - checkIfAlive(); - - if (null != mNetworkConnectivityReceiver) { - // mNetworkConnectivityReceiver is a broadcastReceiver - // but some users reported that the network updates were not dispatched - mNetworkConnectivityReceiver.checkNetworkConnection(mAppContent); - } - - if (null != mCallsManager) { - mCallsManager.unpauseTurnServerRefresh(); - } - - if (null != mEventsThread) { - Log.d(LOG_TAG, "## resumeEventStream() : pickUp"); - mEventsThread.unpause(); - } else { - Log.e(LOG_TAG, "resumeEventStream : mEventsThread is null"); - } - - if (mIsBgCatchupPending) { - mIsBgCatchupPending = false; - Log.d(LOG_TAG, "## resumeEventStream() : cancel bg sync"); - } - - if (null != getMediasCache()) { - getMediasCache().clearShareDecryptedMediaCache(); - } - - if (null != mGroupsManager) { - mGroupsManager.onSessionResumed(); - } - } - - /** - * Trigger a catchup - */ - public void catchupEventStream() { - checkIfAlive(); - - if (null != mEventsThread) { - Log.d(LOG_TAG, "catchupEventStream"); - mEventsThread.catchup(); - } else { - Log.e(LOG_TAG, "catchupEventStream : mEventsThread is null so catchup when the thread will be created"); - mIsBgCatchupPending = true; - } - } - - /** - * Set a global failure callback implementation. - * - * @param failureCallback the failure callback - */ - public void setFailureCallback(ApiFailureCallback failureCallback) { - checkIfAlive(); - - mFailureCallback = failureCallback; - if (mEventsThread != null) { - mEventsThread.setFailureCallback(failureCallback); - } - } - - /** - * Create a new room. - * - * @param callback the async callback once the room is ready - */ - public void createRoom(final ApiCallback callback) { - createRoom(null, null, null, callback); - } - - /** - * Create a new room with given properties. Needs the data handler. - * - * @param name the room name - * @param topic the room topic - * @param alias the room alias - * @param callback the async callback once the room is ready - */ - public void createRoom(String name, String topic, String alias, final ApiCallback callback) { - createRoom(name, topic, RoomDirectoryVisibility.DIRECTORY_VISIBILITY_PRIVATE, alias, null, callback); - } - - /** - * Create a new room with given properties. Needs the data handler. - * - * @param name the room name - * @param topic the room topic - * @param visibility the room visibility - * @param alias the room alias - * @param algorithm the crypto algorithm (null to create an unencrypted room) - * @param callback the async callback once the room is ready - */ - public void createRoom(String name, - String topic, - String visibility, - String alias, - String algorithm, - final ApiCallback callback) { - checkIfAlive(); - - CreateRoomParams params = new CreateRoomParams(); - params.name = !TextUtils.isEmpty(name) ? name : null; - params.topic = !TextUtils.isEmpty(topic) ? topic : null; - params.visibility = !TextUtils.isEmpty(visibility) ? visibility : null; - params.roomAliasName = !TextUtils.isEmpty(alias) ? alias : null; - params.addCryptoAlgorithm(algorithm); - - createRoom(params, callback); - } - - /** - * Create an encrypted room. - * - * @param algorithm the encryption algorithm. - * @param callback the async callback once the room is ready - */ - public void createEncryptedRoom(String algorithm, final ApiCallback callback) { - CreateRoomParams params = new CreateRoomParams(); - params.addCryptoAlgorithm(algorithm); - createRoom(params, callback); - } - - /** - * Create a direct message room with one participant.
- * The participant can be a user ID or mail address. Once the room is created, on success, the room - * is set as a "direct message" with the participant. - * - * @param aParticipantUserId user ID (or user mail) to be invited in the direct message room - * @param aCreateRoomCallBack async call back response - * @return true if the invite was performed, false otherwise - */ - public boolean createDirectMessageRoom(final String aParticipantUserId, final ApiCallback aCreateRoomCallBack) { - return createDirectMessageRoom(aParticipantUserId, null, aCreateRoomCallBack); - } - - /** - * Create a direct message room with one participant.
- * The participant can be a user ID or mail address. Once the room is created, on success, the room - * is set as a "direct message" with the participant. - * - * @param aParticipantUserId user ID (or user mail) to be invited in the direct message room - * @param algorithm the crypto algorithm (null to create an unencrypted room) - * @param aCreateRoomCallBack async call back response - * @return true if the invite was performed, false otherwise - */ - public boolean createDirectMessageRoom(final String aParticipantUserId, final String algorithm, final ApiCallback aCreateRoomCallBack) { - boolean retCode = false; - - if (!TextUtils.isEmpty(aParticipantUserId)) { - retCode = true; - CreateRoomParams params = new CreateRoomParams(); - - params.addCryptoAlgorithm(algorithm); - params.setDirectMessage(); - params.addParticipantIds(mHsConfig, mCredentials, Arrays.asList(aParticipantUserId)); - - createRoom(params, aCreateRoomCallBack); - } - - return retCode; - } - - /** - * Finalise the created room as a direct chat one. - * - * @param roomId the room id - * @param userId the user id - * @param callback the asynchronous callback - */ - private void finalizeDMRoomCreation(final String roomId, String userId, final ApiCallback callback) { - final String fRoomId = roomId; - - toggleDirectChatRoom(roomId, userId, new SimpleApiCallback(callback) { - @Override - public void onSuccess(Void info) { - Room room = getDataHandler().getRoom(fRoomId); - - if (null != room) { - room.markAllAsRead(null); - } - - if (null != callback) { - callback.onSuccess(fRoomId); - } - } - }); - } - - /** - * Create a new room with given properties. - * - * @param params the creation parameters. - * @param callback the async callback once the room is ready - */ - public void createRoom(final CreateRoomParams params, final ApiCallback callback) { - mRoomsRestClient.createRoom(params, new SimpleApiCallback(callback) { - @Override - public void onSuccess(CreateRoomResponse info) { - final String roomId = info.roomId; - final Room createdRoom = mDataHandler.getRoom(roomId); - - // the creation events are not be called during the creation - if (!createdRoom.isJoined()) { - createdRoom.setOnInitialSyncCallback(new SimpleApiCallback(callback) { - @Override - public void onSuccess(Void info) { - createdRoom.markAllAsRead(null); - - if (params.isDirect()) { - finalizeDMRoomCreation(roomId, params.getFirstInvitedUserId(), callback); - } else { - callback.onSuccess(roomId); - } - } - }); - } else { - createdRoom.markAllAsRead(null); - - if (params.isDirect()) { - finalizeDMRoomCreation(roomId, params.getFirstInvitedUserId(), callback); - } else { - callback.onSuccess(roomId); - } - } - } - }); - } - - /** - * Join a room by its roomAlias - * - * @param roomIdOrAlias the room alias - * @param callback the async callback once the room is joined. The RoomId is provided. - */ - public void joinRoom(String roomIdOrAlias, final ApiCallback callback) { - checkIfAlive(); - - // sanity check - if ((null != mDataHandler) && (null != roomIdOrAlias)) { - mDataRetriever.getRoomsRestClient().joinRoom(roomIdOrAlias, new SimpleApiCallback(callback) { - @Override - public void onSuccess(final RoomResponse roomResponse) { - final String roomId = roomResponse.roomId; - Room joinedRoom = mDataHandler.getRoom(roomId); - - // wait until the initial sync is done - if (!joinedRoom.isJoined()) { - joinedRoom.setOnInitialSyncCallback(new SimpleApiCallback(callback) { - @Override - public void onSuccess(Void info) { - callback.onSuccess(roomId); - } - }); - } else { - // to initialise the notification counters - joinedRoom.markAllAsRead(null); - callback.onSuccess(roomId); - } - } - }); - } - } - - /** - * Send the read receipts to the latest room messages. - * - * @param rooms the rooms list - * @param callback the asynchronous callback - */ - public void markRoomsAsRead(final Collection rooms, final ApiCallback callback) { - if ((null == rooms) || (0 == rooms.size())) { - if (null != callback) { - new Handler(Looper.getMainLooper()).post(new Runnable() { - @Override - public void run() { - callback.onSuccess(null); - } - }); - } - return; - } - - markRoomsAsRead(rooms.iterator(), callback); - } - - /** - * Send the read receipts to the latest room messages. - * - * @param roomsIterator the rooms list iterator - * @param callback the asynchronous callback - */ - private void markRoomsAsRead(final Iterator roomsIterator, final ApiCallback callback) { - if (roomsIterator.hasNext()) { - Room room = (Room) roomsIterator.next(); - boolean isRequestSent = false; - - if (mNetworkConnectivityReceiver.isConnected()) { - isRequestSent = room.markAllAsRead(new SimpleApiCallback(callback) { - @Override - public void onSuccess(Void anything) { - markRoomsAsRead(roomsIterator, callback); - } - }); - } else { - // update the local data - room.sendReadReceipt(); - } - - if (!isRequestSent) { - markRoomsAsRead(roomsIterator, callback); - } - - } else { - if (null != callback) { - new Handler(Looper.getMainLooper()).post(new Runnable() { - @Override - public void run() { - callback.onSuccess(null); - } - }); - } - } - } - - /** - * Retrieve user matrix id from a 3rd party id. - * - * @param address the user id. - * @param media the media. - * @param callback the 3rd party callback - */ - public void lookup3Pid(String address, String media, final ApiCallback callback) { - checkIfAlive(); - - mThirdPidRestClient.lookup3Pid(address, media, callback); - } - - /** - * Retrieve user matrix id from a 3rd party id. - * - * @param addresses 3rd party ids - * @param mediums the medias. - * @param callback the 3rd parties callback - */ - public void lookup3Pids(List addresses, List mediums, ApiCallback> callback) { - checkIfAlive(); - - mThirdPidRestClient.lookup3Pids(addresses, mediums, callback); - } - - /** - * Perform a remote text search. - * - * @param text the text to search for. - * @param rooms a list of rooms to search in. nil means all rooms the user is in. - * @param beforeLimit the number of events to get before the matching results. - * @param afterLimit the number of events to get after the matching results. - * @param nextBatch the token to pass for doing pagination from a previous response. - * @param callback the request callback - */ - public void searchMessageText(String text, - List rooms, - int beforeLimit, - int afterLimit, - String nextBatch, - final ApiCallback callback) { - checkIfAlive(); - if (null != callback) { - mEventsRestClient.searchMessagesByText(text, rooms, beforeLimit, afterLimit, nextBatch, callback); - } - } - - /** - * Perform a remote text search. - * - * @param text the text to search for. - * @param rooms a list of rooms to search in. nil means all rooms the user is in. - * @param nextBatch the token to pass for doing pagination from a previous response. - * @param callback the request callback - */ - public void searchMessagesByText(String text, List rooms, String nextBatch, final ApiCallback callback) { - checkIfAlive(); - if (null != callback) { - mEventsRestClient.searchMessagesByText(text, rooms, 0, 0, nextBatch, callback); - } - } - - /** - * Perform a remote text search. - * - * @param text the text to search for. - * @param nextBatch the token to pass for doing pagination from a previous response. - * @param callback the request callback - */ - public void searchMessagesByText(String text, String nextBatch, final ApiCallback callback) { - checkIfAlive(); - if (null != callback) { - mEventsRestClient.searchMessagesByText(text, null, 0, 0, nextBatch, callback); - } - } - - /** - * Cancel any pending search request - */ - public void cancelSearchMessagesByText() { - checkIfAlive(); - mEventsRestClient.cancelSearchMessagesByText(); - } - - /** - * Perform a remote text search for a dedicated media types list - * - * @param name the text to search for. - * @param rooms a list of rooms to search in. nil means all rooms the user is in. - * @param nextBatch the token to pass for doing pagination from a previous response. - * @param callback the request callback - */ - public void searchMediasByName(String name, List rooms, String nextBatch, final ApiCallback callback) { - checkIfAlive(); - - if (null != callback) { - mEventsRestClient.searchMediasByText(name, rooms, 0, 0, nextBatch, callback); - } - } - - /** - * Cancel any pending file search request - */ - public void cancelSearchMediasByText() { - checkIfAlive(); - mEventsRestClient.cancelSearchMediasByText(); - } - - /** - * Perform a remote users search by name / user id. - * - * @param name the text to search for. - * @param limit the maximum number of items to retrieve (can be null) - * @param userIdsFilter the user ids filter (can be null) - * @param callback the callback - */ - public void searchUsers(String name, Integer limit, Set userIdsFilter, final ApiCallback callback) { - checkIfAlive(); - - if (null != callback) { - mEventsRestClient.searchUsers(name, limit, userIdsFilter, callback); - } - } - - /** - * Cancel any pending user search - */ - public void cancelUsersSearch() { - checkIfAlive(); - mEventsRestClient.cancelUsersSearch(); - } - - - /** - * Return the fulfilled active BingRule for the event. - * - * @param event the event - * @return the fulfilled bingRule - */ - public BingRule fulfillRule(Event event) { - checkIfAlive(); - return mBingRulesManager.fulfilledBingRule(event); - } - - /** - * @return true if the calls are supported - */ - public boolean isVoipCallSupported() { - if (null != mCallsManager) { - return mCallsManager.isSupported(); - } else { - return false; - } - } - - /** - * Get the list of rooms that are tagged the specified tag. - * The returned array is ordered according to the room tag order. - * - * @param tag RoomTag.ROOM_TAG_XXX values - * @return the rooms list. - */ - public List roomsWithTag(final String tag) { - final List taggedRooms = new ArrayList<>(); - - // sanity check - if (null == mDataHandler.getStore()) { - return taggedRooms; - } - - if (!TextUtils.equals(tag, RoomTag.ROOM_TAG_NO_TAG)) { - final Collection rooms = mDataHandler.getStore().getRooms(); - for (Room room : rooms) { - if (null != room.getAccountData().roomTag(tag)) { - taggedRooms.add(room); - } - } - if (taggedRooms.size() > 0) { - Collections.sort(taggedRooms, new RoomComparatorWithTag(tag)); - } - } else { - final Collection rooms = mDataHandler.getStore().getRooms(); - for (Room room : rooms) { - if (!room.getAccountData().hasTags()) { - taggedRooms.add(room); - } - } - } - - return taggedRooms; - } - - /** - * Get the list of roomIds that are tagged the specified tag. - * The returned array is ordered according to the room tag order. - * - * @param tag RoomTag.ROOM_TAG_XXX values - * @return the room IDs list. - */ - public List roomIdsWithTag(final String tag) { - List roomsWithTag = roomsWithTag(tag); - - List roomIdsList = new ArrayList<>(); - - for (Room room : roomsWithTag) { - roomIdsList.add(room.getRoomId()); - } - - return roomIdsList; - } - - /** - * Compute the tag order to use for a room tag so that the room will appear in the expected position - * in the list of rooms stamped with this tag. - * - * @param index the targeted index of the room in the list of rooms with the tag `tag`. - * @param originIndex the origin index. Integer.MAX_VALUE if there is none. - * @param tag the tag - * @return the tag order to apply to get the expected position. - */ - public Double tagOrderToBeAtIndex(int index, int originIndex, String tag) { - // Algo (and the [0.0, 1.0] assumption) inspired from matrix-react-sdk: - // We sort rooms by the lexicographic ordering of the 'order' metadata on their tags. - // For convenience, we calculate this for now a floating point number between 0.0 and 1.0. - - Double orderA = 0.0; // by default we're next to the beginning of the list - Double orderB = 1.0; // by default we're next to the end of the list too - - List roomsWithTag = roomsWithTag(tag); - - if (roomsWithTag.size() > 0) { - // when an object is moved down, the index must be incremented - // because the object will be removed from the list to be inserted after its destination - if ((originIndex != Integer.MAX_VALUE) && (originIndex < index)) { - index++; - } - - if (index > 0) { - // Bound max index to the array size - int prevIndex = (index < roomsWithTag.size()) ? index : roomsWithTag.size(); - - RoomTag prevTag = roomsWithTag.get(prevIndex - 1).getAccountData().roomTag(tag); - - if (null == prevTag.mOrder) { - Log.e(LOG_TAG, "computeTagOrderForRoom: Previous room in sublist has no ordering metadata. This should never happen."); - } else { - orderA = prevTag.mOrder; - } - } - - if (index <= roomsWithTag.size() - 1) { - RoomTag nextTag = roomsWithTag.get(index).getAccountData().roomTag(tag); - - if (null == nextTag.mOrder) { - Log.e(LOG_TAG, "computeTagOrderForRoom: Next room in sublist has no ordering metadata. This should never happen."); - } else { - orderB = nextTag.mOrder; - } - } - } - - return (orderA + orderB) / 2.0; - } - - /** - * Toggles the direct chat status of a room.
- * Create a new direct chat room in the account data section if the room does not exist, - * otherwise the room is removed from the account data section. - * Direct chat room user ID choice algorithm:
- * 1- oldest joined room member - * 2- oldest invited room member - * 3- the user himself - * - * @param roomId the room roomId - * @param aParticipantUserId the participant user id - * @param callback the asynchronous callback - */ - public void toggleDirectChatRoom(final String roomId, - @Nullable final String aParticipantUserId, - final ApiCallback callback) { - IMXStore store = getDataHandler().getStore(); - Room room = store.getRoom(roomId); - - if (null != room) { - if (getDataHandler().getDirectChatRoomIdsList().contains(roomId)) { - // The room is already seen as direct chat - removeDirectChatRoomFromAccountData(roomId, callback); - } else { - // The room was not yet seen as direct chat - if (null == aParticipantUserId) { - searchOtherUserInRoomToCreateDirectChat(room, new SimpleApiCallback(callback) { - @Override - public void onSuccess(String info) { - addDirectChatRoomToAccountData(roomId, info, callback); - } - }); - } else { - addDirectChatRoomToAccountData(roomId, aParticipantUserId, callback); - } - } - } else { - if (callback != null) { - callback.onUnexpectedError(new Exception("Unknown room")); - } - } - } - - /** - * Search another user in the room to create a direct chat - * - * @param room the room to search in - * @param callback the callback to get the selected user id - */ - private void searchOtherUserInRoomToCreateDirectChat(@NonNull final Room room, - @NonNull final ApiCallback callback) { - room.getActiveMembersAsync(new SimpleApiCallback>(callback) { - @Override - public void onSuccess(List members) { - // should never happen but it was reported by a GA issue - if (members.isEmpty()) { - callback.onUnexpectedError(new Exception("Error")); - - return; - } - - RoomMember directChatMember = null; - - if (members.size() > 1) { - // sort algo: oldest join first, then oldest invited - Collections.sort(members, new Comparator() { - @Override - public int compare(RoomMember r1, RoomMember r2) { - int res; - long diff; - - if (RoomMember.MEMBERSHIP_JOIN.equals(r2.membership) && RoomMember.MEMBERSHIP_INVITE.equals(r1.membership)) { - res = 1; - } else if (r2.membership.equals(r1.membership)) { - diff = r1.getOriginServerTs() - r2.getOriginServerTs(); - res = (0 == diff) ? 0 : ((diff > 0) ? 1 : -1); - } else { - res = -1; - } - return res; - } - }); - - int nextIndexSearch = 0; - - // take the oldest join member - if (!TextUtils.equals(members.get(0).getUserId(), getMyUserId())) { - if (RoomMember.MEMBERSHIP_JOIN.equals(members.get(0).membership)) { - directChatMember = members.get(0); - } - } else { - nextIndexSearch = 1; - if (RoomMember.MEMBERSHIP_JOIN.equals(members.get(1).membership)) { - directChatMember = members.get(1); - } - } - - // no join member found, test the oldest join member - if (null == directChatMember) { - if (RoomMember.MEMBERSHIP_INVITE.equals(members.get(nextIndexSearch).membership)) { - directChatMember = members.get(nextIndexSearch); - } - } - } - - // last option: get the logged user - if (null == directChatMember) { - directChatMember = members.get(0); - } - - callback.onSuccess(directChatMember.getUserId()); - } - }); - } - - /** - * Add the room to the direct chat room list in AccountData - * - * @param roomId the room roomId - * @param chosenUserId userId of the direct chat room - * @param callback the asynchronous callback - */ - private void addDirectChatRoomToAccountData(String roomId, - @NonNull String chosenUserId, - ApiCallback callback) { - IMXStore store = getDataHandler().getStore(); - Map> params; - - if (null != store.getDirectChatRoomsDict()) { - params = new HashMap<>(store.getDirectChatRoomsDict()); - } else { - params = new HashMap<>(); - } - - List roomIdsList = new ArrayList<>(); - - // search if there is an entry with the same user - if (params.containsKey(chosenUserId)) { - roomIdsList = new ArrayList<>(params.get(chosenUserId)); - } - - roomIdsList.add(roomId); // update room list with the new room - params.put(chosenUserId, roomIdsList); - - // Store and upload the updated map - getDataHandler().setDirectChatRoomsMap(params, callback); - } - - /** - * Remove the room to the direct chat room list in AccountData - * - * @param roomId the room roomId - * @param callback the asynchronous callback - */ - private void removeDirectChatRoomFromAccountData(String roomId, - ApiCallback callback) { - IMXStore store = getDataHandler().getStore(); - - Map> params; - - if (null != store.getDirectChatRoomsDict()) { - params = new HashMap<>(store.getDirectChatRoomsDict()); - } else { - params = new HashMap<>(); - } - - // remove the current room from the direct chat list rooms - if (null != store.getDirectChatRoomsDict()) { - List keysList = new ArrayList<>(params.keySet()); - - for (String key : keysList) { - List roomIdsList = params.get(key); - if (roomIdsList.contains(roomId)) { - roomIdsList.remove(roomId); - - if (roomIdsList.isEmpty()) { - // Remove this entry - params.remove(key); - } - } - } - } else { - // should not happen: if the room has to be removed, it means the room has been - // previously detected as being part of the listOfList - Log.e(LOG_TAG, "## removeDirectChatRoomFromAccountData(): failed to remove a direct chat room (not seen as direct chat room)"); - if (callback != null) { - callback.onUnexpectedError(new Exception("Error")); - } - return; - } - - // Store and upload the updated map - getDataHandler().setDirectChatRoomsMap(params, callback); - } - - /** - * Update the account password - * - * @param oldPassword the former account password - * @param newPassword the new account password - * @param callback the callback - */ - public void updatePassword(String oldPassword, String newPassword, ApiCallback callback) { - mProfileRestClient.updatePassword(getMyUserId(), oldPassword, newPassword, callback); - } - - /** - * Reset the password to a new one. - * - * @param newPassword the new password - * @param threepid_creds the three pids. - * @param callback the callback - */ - public void resetPassword(final String newPassword, final Map threepid_creds, final ApiCallback callback) { - mProfileRestClient.resetPassword(newPassword, threepid_creds, callback); - } - - /** - * Triggers a request to update the userIds to ignore - * - * @param userIds the userIds to ignore - * @param callback the callback - */ - private void updateUsers(List userIds, ApiCallback callback) { - Map ignoredUsersDict = new HashMap<>(); - - for (String userId : userIds) { - ignoredUsersDict.put(userId, new HashMap<>()); - } - - Map params = new HashMap<>(); - params.put(AccountDataRestClient.ACCOUNT_DATA_KEY_IGNORED_USERS, ignoredUsersDict); - - mAccountDataRestClient.setAccountData(getMyUserId(), AccountDataRestClient.ACCOUNT_DATA_TYPE_IGNORED_USER_LIST, params, callback); - } - - /** - * Tells if an user is in the ignored user ids list - * - * @param userId the user id to test - * @return true if the user is ignored - */ - public boolean isUserIgnored(String userId) { - if (null != userId) { - return getDataHandler().getIgnoredUserIds().indexOf(userId) >= 0; - } - - return false; - } - - /** - * Ignore a list of users. - * - * @param userIds the user ids list to ignore - * @param callback the result callback - */ - public void ignoreUsers(List userIds, ApiCallback callback) { - List curUserIdsToIgnore = getDataHandler().getIgnoredUserIds(); - List userIdsToIgnore = new ArrayList<>(getDataHandler().getIgnoredUserIds()); - - // something to add - if ((null != userIds) && (userIds.size() > 0)) { - // add the new one - for (String userId : userIds) { - if (userIdsToIgnore.indexOf(userId) < 0) { - userIdsToIgnore.add(userId); - } - } - - // some items have been added - if (curUserIdsToIgnore.size() != userIdsToIgnore.size()) { - updateUsers(userIdsToIgnore, callback); - } - } - } - - /** - * Unignore a list of users. - * - * @param userIds the user ids list to unignore - * @param callback the result callback - */ - public void unIgnoreUsers(List userIds, ApiCallback callback) { - List curUserIdsToIgnore = getDataHandler().getIgnoredUserIds(); - List userIdsToIgnore = new ArrayList<>(getDataHandler().getIgnoredUserIds()); - - // something to add - if ((null != userIds) && (userIds.size() > 0)) { - // add the new one - for (String userId : userIds) { - userIdsToIgnore.remove(userId); - } - - // some items have been added - if (curUserIdsToIgnore.size() != userIdsToIgnore.size()) { - updateUsers(userIdsToIgnore, callback); - } - } - } - - /** - * @return the network receiver. - */ - public NetworkConnectivityReceiver getNetworkConnectivityReceiver() { - return mNetworkConnectivityReceiver; - } - - - /** - * Ask the home server if the lazy loading of room members is supported. - * - * @param callback the callback, to be notified if the server actually support the lazy loading. True if supported - */ - public void canEnableLazyLoading(final ApiCallback callback) { - // Check that the server support the lazy loading - mLoginRestClient.getVersions(new SimpleApiCallback(callback) { - @Override - public void onSuccess(Versions info) { - // Check if we can enable lazyLoading - callback.onSuccess(VersionsUtil.supportLazyLoadMembers(info)); - } - }); - } - - /** - * Invalidate the access token, so that it can no longer be used for authorization. - * - * @param context the application context - * @param callback the callback success and failure callback - */ - public void logout(final Context context, final ApiCallback callback) { - synchronized (this) { - if (!mIsAliveSession) { - Log.e(LOG_TAG, "## logout() was already called"); - return; - } - - mIsAliveSession = false; - } - - // Clear crypto data - // For security and because it will be no more useful as we will get a new device id - // on the next log in - enableCrypto(false, null); - - mLoginRestClient.logout(new ApiCallback() { - - private void clearData() { - // required else the clear won't be done - mIsAliveSession = true; - - clear(context, new SimpleApiCallback() { - @Override - public void onSuccess(Void info) { - if (null != callback) { - callback.onSuccess(null); - } - } - }); - } - - @Override - public void onSuccess(JsonObject info) { - Log.d(LOG_TAG, "## logout() : succeed -> clearing the application data "); - clearData(); - } - - private void onError(String errorMessage) { - Log.e(LOG_TAG, "## logout() : failed " + errorMessage); - clearData(); - } - - @Override - public void onNetworkError(Exception e) { - onError(e.getMessage()); - } - - @Override - public void onMatrixError(MatrixError e) { - onError(e.getMessage()); - } - - @Override - public void onUnexpectedError(Exception e) { - onError(e.getMessage()); - } - }); - } - - /** - * Deactivate the account. - * - * @param context the application context - * @param type type of authentication - * @param userPassword current password - * @param eraseUserData true to also erase all the user data - * @param callback the success and failure callback - */ - public void deactivateAccount(final Context context, - final String type, - final String userPassword, - final boolean eraseUserData, - final ApiCallback callback) { - mProfileRestClient.deactivateAccount(type, getMyUserId(), userPassword, eraseUserData, new SimpleApiCallback(callback) { - - @Override - public void onSuccess(Void info) { - Log.d(LOG_TAG, "## deactivateAccount() : succeed -> clearing the application data "); - - // Clear crypto data - // For security and because it will be no more useful as we will get a new device id - // on the next log in - enableCrypto(false, null); - - clear(context, new SimpleApiCallback(callback) { - @Override - public void onSuccess(Void info) { - if (null != callback) { - callback.onSuccess(null); - } - } - }); - } - }); - } - - /** - * Update the URL preview status by default - * - * @param status the status - * @param callback - */ - public void setURLPreviewStatus(final boolean status, final ApiCallback callback) { - Map params = new HashMap<>(); - params.put(AccountDataRestClient.ACCOUNT_DATA_KEY_URL_PREVIEW_DISABLE, !status); - - Log.d(LOG_TAG, "## setURLPreviewStatus() : status " + status); - mAccountDataRestClient.setAccountData(getMyUserId(), AccountDataRestClient.ACCOUNT_DATA_TYPE_PREVIEW_URLS, params, new ApiCallback() { - @Override - public void onSuccess(Void info) { - Log.d(LOG_TAG, "## setURLPreviewStatus() : succeeds"); - - getDataHandler().getStore().setURLPreviewEnabled(status); - if (null != callback) { - callback.onSuccess(null); - } - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "## setURLPreviewStatus() : failed " + e.getMessage(), e); - callback.onNetworkError(e); - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "## setURLPreviewStatus() : failed " + e.getMessage()); - callback.onMatrixError(e); - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "## setURLPreviewStatus() : failed " + e.getMessage(), e); - callback.onUnexpectedError(e); - } - }); - } - - /** - * Add user widget to the user Account Data - * - * @param params - * @param callback - */ - public void addUserWidget(final Map params, final ApiCallback callback) { - Log.d(LOG_TAG, "## addUserWidget()"); - - mAccountDataRestClient.setAccountData(getMyUserId(), AccountDataRestClient.ACCOUNT_DATA_TYPE_WIDGETS, params, new ApiCallback() { - @Override - public void onSuccess(Void info) { - Log.d(LOG_TAG, "## addUserWidget() : succeeds"); - - getDataHandler().getStore().setUserWidgets(params); - if (null != callback) { - callback.onSuccess(null); - } - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "## addUserWidget() : failed " + e.getMessage(), e); - callback.onNetworkError(e); - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "## addUserWidget() : failed " + e.getMessage()); - callback.onMatrixError(e); - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "## addUserWidget() : failed " + e.getMessage(), e); - callback.onUnexpectedError(e); - } - }); - } - - /** - * Tells if the global URL preview settings is enabled - * - * @return true if it is enabled. - */ - public boolean isURLPreviewEnabled() { - return getDataHandler().getStore().isURLPreviewEnabled(); - } - - /** - * Get user widget from user AccountData - * - * @return - */ - public Map getUserWidgets() { - return getDataHandler().getStore().getUserWidgets(); - } - - //============================================================================================================== - // Crypto - //============================================================================================================== - - /** - * The module that manages E2E encryption. - * Null if the feature is not enabled - */ - private MXCrypto mCrypto; - - /** - * @return the crypto instance - */ - public MXCrypto getCrypto() { - return mCrypto; - } - - /** - * @return true if the crypto is enabled - */ - public boolean isCryptoEnabled() { - return null != mCrypto; - } - - /** - * enable encryption by default when launching the session - */ - private boolean mEnableCryptoWhenStartingMXSession = false; - - /** - * Enable the crypto when initializing a new session. - */ - public void enableCryptoWhenStarting() { - mEnableCryptoWhenStartingMXSession = true; - } - - /** - * Optional set of parameters used to configure/customize the e2e encryption - */ - @Nullable - private static MXCryptoConfig sCryptoConfig; - - /** - * Define the set of parameters used to configure/customize the e2e encryption - * This configuration must be set before instantiating the session - */ - public static void setCryptoConfig(@Nullable MXCryptoConfig cryptoConfig) { - sCryptoConfig = cryptoConfig; - } - - /** - * When the encryption is toogled, the room summaries must be updated - * to display the right messages. - */ - private void decryptRoomSummaries() { - if (null != getDataHandler().getStore()) { - Collection summaries = getDataHandler().getStore().getSummaries(); - - for (RoomSummary summary : summaries) { - mDataHandler.decryptEvent(summary.getLatestReceivedEvent(), null); - } - } - } - - /** - * Check if the crypto engine is properly initialized. - * Launch it it is was not yet done. - */ - public void checkCrypto() { - MXFileCryptoStore fileCryptoStore = new MXFileCryptoStore(mEnableFileEncryption); - fileCryptoStore.initWithCredentials(mAppContent, mCredentials); - - if ((fileCryptoStore.hasData() || mEnableCryptoWhenStartingMXSession) && (null == mCrypto)) { - boolean isStoreLoaded = false; - try { - // open the store - fileCryptoStore.open(); - isStoreLoaded = true; - } catch (UnsatisfiedLinkError e) { - Log.e(LOG_TAG, "## checkCrypto() failed " + e.getMessage(), e); - } - - if (!isStoreLoaded) { - // load again the olm manager - // reported by rageshake, it seems that the olm lib is unloaded. - mOlmManager = new OlmManager(); - - try { - // open the store - fileCryptoStore.open(); - isStoreLoaded = true; - } catch (UnsatisfiedLinkError e) { - Log.e(LOG_TAG, "## checkCrypto() failed 2 " + e.getMessage(), e); - } - } - - if (!isStoreLoaded) { - Log.e(LOG_TAG, "## checkCrypto() : cannot enable the crypto because of olm lib"); - return; - } - - mCrypto = new MXCrypto(MXSession.this, fileCryptoStore, sCryptoConfig); - mDataHandler.setCrypto(mCrypto); - // the room summaries are not stored with decrypted content - decryptRoomSummaries(); - - Log.d(LOG_TAG, "## checkCrypto() : the crypto engine is ready"); - } else if (mDataHandler.getCrypto() != mCrypto) { - Log.e(LOG_TAG, "## checkCrypto() : the data handler crypto was not initialized"); - mDataHandler.setCrypto(mCrypto); - } - } - - /** - * Enable / disable the crypto. - * - * @param cryptoEnabled true to enable the crypto - * @param callback the asynchronous callback called when the action has been done - */ - public void enableCrypto(boolean cryptoEnabled, final ApiCallback callback) { - if (cryptoEnabled != isCryptoEnabled()) { - if (cryptoEnabled) { - Log.d(LOG_TAG, "Crypto is enabled"); - MXFileCryptoStore fileCryptoStore = new MXFileCryptoStore(mEnableFileEncryption); - fileCryptoStore.initWithCredentials(mAppContent, mCredentials); - fileCryptoStore.open(); - mCrypto = new MXCrypto(this, fileCryptoStore, sCryptoConfig); - mCrypto.start(true, new SimpleApiCallback(callback) { - @Override - public void onSuccess(Void info) { - decryptRoomSummaries(); - if (null != callback) { - callback.onSuccess(null); - } - } - }); - } else if (null != mCrypto) { - Log.d(LOG_TAG, "Crypto is disabled"); - IMXCryptoStore store = mCrypto.mCryptoStore; - mCrypto.close(); - store.deleteStore(); - mCrypto = null; - mDataHandler.setCrypto(null); - - decryptRoomSummaries(); - - if (null != callback) { - callback.onSuccess(null); - } - } - - mDataHandler.setCrypto(mCrypto); - } else { - if (null != callback) { - callback.onSuccess(null); - } - } - } - - /** - * Retrieves the devices list - * - * @param callback the asynchronous callback - */ - public void getDevicesList(ApiCallback callback) { - mCryptoRestClient.getDevices(callback); - } - - /** - * Set a device name. - * - * @param deviceId the device id - * @param deviceName the device name - * @param callback the asynchronous callback - */ - public void setDeviceName(final String deviceId, final String deviceName, final ApiCallback callback) { - mCryptoRestClient.setDeviceName(deviceId, deviceName, callback); - } - - /** - * Delete a device - * - * @param deviceId the device id - * @param password the passwoerd - * @param callback the asynchronous callback. - */ - public void deleteDevice(final String deviceId, final String password, final ApiCallback callback) { - mCryptoRestClient.deleteDevice(deviceId, new DeleteDeviceParams(), new SimpleApiCallback(callback) { - @Override - public void onSuccess(Void info) { - // should never happen - if (null != callback) { - callback.onSuccess(null); - } - } - - @Override - public void onMatrixError(MatrixError matrixError) { - Log.d(LOG_TAG, "## deleteDevice() : onMatrixError " + matrixError.getMessage()); - RegistrationFlowResponse registrationFlowResponse = null; - - // expected status code is 401 - if ((null != matrixError.mStatus) && (matrixError.mStatus == 401)) { - try { - registrationFlowResponse = JsonUtils.toRegistrationFlowResponse(matrixError.mErrorBodyAsString); - } catch (Exception castExcept) { - Log.e(LOG_TAG, "## deleteDevice(): Received status 401 - Exception - JsonUtils.toRegistrationFlowResponse()", castExcept); - } - } else { - Log.d(LOG_TAG, "## deleteDevice(): Received not expected status 401 =" + matrixError.mStatus); - } - - List stages = new ArrayList<>(); - - // check if the server response can be casted - if ((null != registrationFlowResponse) - && (null != registrationFlowResponse.flows) - && !registrationFlowResponse.flows.isEmpty()) { - for (LoginFlow flow : registrationFlowResponse.flows) { - if (null != flow.stages) { - stages.addAll(flow.stages); - } - } - } - - if (!stages.isEmpty()) { - DeleteDeviceParams params = new DeleteDeviceParams(); - params.auth = new DeleteDeviceAuth(); - params.auth.session = registrationFlowResponse.session; - params.auth.user = mCredentials.getUserId(); - params.auth.password = password; - - Log.d(LOG_TAG, "## deleteDevice() : supported stages " + stages); - - deleteDevice(deviceId, params, stages, callback); - } else { - if (null != callback) { - callback.onMatrixError(matrixError); - } - } - } - }); - } - - /** - * Delete a device. - * - * @param deviceId the device id. - * @param params the delete device params - * @param stages the supported stages - * @param callback the asynchronous callback - */ - private void deleteDevice(final String deviceId, final DeleteDeviceParams params, final List stages, final ApiCallback callback) { - // test the first one - params.auth.type = stages.get(0); - stages.remove(0); - - mCryptoRestClient.deleteDevice(deviceId, params, new SimpleApiCallback(callback) { - @Override - public void onSuccess(Void info) { - if (null != callback) { - callback.onSuccess(null); - } - } - - @Override - public void onMatrixError(MatrixError matrixError) { - boolean has401Error = (null != matrixError.mStatus) && (matrixError.mStatus == 401); - - // failed, try next flow type - if ((has401Error || TextUtils.equals(matrixError.errcode, MatrixError.FORBIDDEN) || TextUtils.equals(matrixError.errcode, MatrixError.UNKNOWN)) - && !stages.isEmpty()) { - deleteDevice(deviceId, params, stages, callback); - } else { - if (null != callback) { - callback.onMatrixError(matrixError); - } - } - } - }); - } - - /** - * Gets a bearer token from the homeserver that the user can - * present to a third party in order to prove their ownership - * of the Matrix account they are logged into. - * - * @param callback the asynchronous callback called when finished - */ - public void openIdToken(final ApiCallback> callback) { - mAccountDataRestClient.openIdToken(getMyUserId(), callback); - } - - /** - * @return the groups manager - */ - public GroupsManager getGroupsManager() { - return mGroupsManager; - } - - /* ========================================================================================== - * Builder - * ========================================================================================== */ - - public static class Builder { - - private MXSession mxSession; - private SessionParams sessionParams; - - public Builder(SessionParams sessionParams, MXDataHandler dataHandler, Context context) { - mxSession = new MXSession(sessionParams, dataHandler, context); - } - - public Builder withFileEncryption(boolean enableFileEncryption) { - mxSession.mEnableFileEncryption = enableFileEncryption; - return this; - } - - /** - * Create a pusher rest client, overriding the push server url if necessary - * - * @param pushServerUrl the push server url, or null or empty to use the default PushersRestClient - * @return this builder, to chain calls - */ - public Builder withPushServerUrl(@Nullable String pushServerUrl) { - // If not empty, create a special PushersRestClient - PushersRestClient pushersRestClient = null; - - if (!TextUtils.isEmpty(pushServerUrl)) { - // pusher uses a custom server - try { - HomeServerConnectionConfig alteredHsConfig = new HomeServerConnectionConfig.Builder() - .withHomeServerUri(Uri.parse(pushServerUrl)) - .build(); - pushersRestClient = new PushersRestClient(new SessionParams(sessionParams.getCredentials(), alteredHsConfig)); - } catch (Exception e) { - Log.e(LOG_TAG, "## withPushServerUrl() failed " + e.getMessage(), e); - } - } - - if (null != pushersRestClient) { - // Replace the existing client - mxSession.mPushersRestClient = pushersRestClient; - } - - return this; - } - - /** - * Set the metrics listener of this session - * - * @param metricsListener the metrics listener - * @return this builder, to chain calls - */ - public Builder withMetricsListener(@Nullable MetricsListener metricsListener) { - mxSession.mMetricsListener = metricsListener; - return this; - } - - /** - * Build the session - * - * @return the build session - */ - public MXSession build() { - return mxSession; - } - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/MxEventDispatcher.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/MxEventDispatcher.java deleted file mode 100644 index 43a46f49..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/MxEventDispatcher.java +++ /dev/null @@ -1,738 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy; - -import android.os.Looper; -import android.support.annotation.Nullable; - -import im.vector.matrix.android.internal.legacy.data.MyUser; -import im.vector.matrix.android.internal.legacy.data.RoomState; -import im.vector.matrix.android.internal.legacy.listeners.IMXEventListener; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.rest.model.User; -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.BingRule; -import im.vector.matrix.android.internal.legacy.util.Log; -import im.vector.matrix.android.internal.legacy.util.MXOsHandler; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * Dispatcher for MXDataHandler - * This class store a list of listener and dispatch event to every listener on the Ui Thread - */ -/* package */ class MxEventDispatcher { - private static final String LOG_TAG = MxEventDispatcher.class.getSimpleName(); - - private final MXOsHandler mUiHandler; - - @Nullable - private IMXEventListener mCryptoEventsListener = null; - - private final Set mEventListeners = new HashSet<>(); - - MxEventDispatcher() { - mUiHandler = new MXOsHandler(Looper.getMainLooper()); - } - - /* ========================================================================================== - * Public utilities - * ========================================================================================== */ - - /** - * Set the crypto events listener, or remove it - * - * @param listener the listener or null to remove the listener - */ - public void setCryptoEventsListener(@Nullable IMXEventListener listener) { - mCryptoEventsListener = listener; - } - - /** - * Add a listener to the listeners list. - * - * @param listener the listener to add. - */ - public void addListener(IMXEventListener listener) { - mEventListeners.add(listener); - } - - /** - * Remove a listener from the listeners list. - * - * @param listener to remove. - */ - public void removeListener(IMXEventListener listener) { - mEventListeners.remove(listener); - } - - /** - * Remove any listener - */ - public void clearListeners() { - mEventListeners.clear(); - } - - /* ========================================================================================== - * Dispatchers - * ========================================================================================== */ - - public void dispatchOnStoreReady() { - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onStoreReady(); - } catch (Exception e) { - Log.e(LOG_TAG, "onStoreReady " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnAccountInfoUpdate(final MyUser myUser) { - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onAccountInfoUpdate(myUser); - } catch (Exception e) { - Log.e(LOG_TAG, "onAccountInfoUpdate " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnPresenceUpdate(final Event event, final User user) { - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onPresenceUpdate(event, user); - } catch (Exception e) { - Log.e(LOG_TAG, "onPresenceUpdate " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnLiveEvent(final Event event, final RoomState roomState) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onLiveEvent(event, roomState); - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onLiveEvent(event, roomState); - } catch (Exception e) { - Log.e(LOG_TAG, "onLiveEvent " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnLiveEventsChunkProcessed(final String startToken, final String toToken) { - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onLiveEventsChunkProcessed(startToken, toToken); - } catch (Exception e) { - Log.e(LOG_TAG, "onLiveEventsChunkProcessed " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnBingEvent(final Event event, final RoomState roomState, final BingRule bingRule, boolean ignoreEvent) { - if (ignoreEvent) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onBingEvent(event, roomState, bingRule); - } catch (Exception e) { - Log.e(LOG_TAG, "onBingEvent " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnEventSentStateUpdated(final Event event, boolean ignoreEvent) { - if (ignoreEvent) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onEventSentStateUpdated(event); - } catch (Exception e) { - Log.e(LOG_TAG, "onEventSentStateUpdated " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnEventSent(final Event event, final String prevEventId, boolean ignoreEvent) { - if (ignoreEvent) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onEventSent(event, prevEventId); - } catch (Exception e) { - Log.e(LOG_TAG, "onEventSent " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnBingRulesUpdate() { - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onBingRulesUpdate(); - } catch (Exception e) { - Log.e(LOG_TAG, "onBingRulesUpdate " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnInitialSyncComplete(final String toToken) { - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onInitialSyncComplete(toToken); - } catch (Exception e) { - Log.e(LOG_TAG, "onInitialSyncComplete " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnCryptoSyncComplete() { - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onCryptoSyncComplete(); - } catch (Exception e) { - Log.e(LOG_TAG, "OnCryptoSyncComplete " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnSyncError(final MatrixError matrixError) { - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onSyncError(matrixError); - } catch (Exception e) { - Log.e(LOG_TAG, "onSyncError " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnNewRoom(final String roomId, boolean ignoreEvent) { - if (ignoreEvent) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onNewRoom(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onNewRoom " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnJoinRoom(final String roomId, boolean ignoreEvent) { - if (ignoreEvent) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onJoinRoom(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onJoinRoom " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnRoomInternalUpdate(final String roomId, boolean ignoreEvent) { - if (ignoreEvent) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onRoomInternalUpdate(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onRoomInternalUpdate " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnLeaveRoom(final String roomId, boolean ignoreEvent) { - if (ignoreEvent) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onLeaveRoom(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onLeaveRoom " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnRoomKick(final String roomId, boolean ignoreEvent) { - if (ignoreEvent) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onRoomKick(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onRoomKick " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnReceiptEvent(final String roomId, final List senderIds, boolean ignoreEvent) { - if (ignoreEvent) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onReceiptEvent(roomId, senderIds); - } catch (Exception e) { - Log.e(LOG_TAG, "onReceiptEvent " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnRoomTagEvent(final String roomId, boolean ignoreEvent) { - if (ignoreEvent) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onRoomTagEvent(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onRoomTagEvent " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnReadMarkerEvent(final String roomId, boolean ignoreEvent) { - if (ignoreEvent) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onReadMarkerEvent(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onReadMarkerEvent " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnRoomFlush(final String roomId, boolean ignoreEvent) { - if (ignoreEvent) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onRoomFlush(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onRoomFlush " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnIgnoredUsersListUpdate() { - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onIgnoredUsersListUpdate(); - } catch (Exception e) { - Log.e(LOG_TAG, "onIgnoredUsersListUpdate " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnToDeviceEvent(final Event event, boolean ignoreEvent) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onToDeviceEvent(event); - } - - if (ignoreEvent) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onToDeviceEvent(event); - } catch (Exception e) { - Log.e(LOG_TAG, "OnToDeviceEvent " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnDirectMessageChatRoomsListUpdate() { - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onDirectMessageChatRoomsListUpdate(); - } catch (Exception e) { - Log.e(LOG_TAG, "onDirectMessageChatRoomsListUpdate " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnEventDecrypted(final Event event) { - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onEventDecrypted(event); - } catch (Exception e) { - Log.e(LOG_TAG, "onDecryptedEvent " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnNewGroupInvitation(final String groupId) { - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onNewGroupInvitation(groupId); - } catch (Exception e) { - Log.e(LOG_TAG, "onNewGroupInvitation " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnJoinGroup(final String groupId) { - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onJoinGroup(groupId); - } catch (Exception e) { - Log.e(LOG_TAG, "onJoinGroup " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnLeaveGroup(final String groupId) { - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onLeaveGroup(groupId); - } catch (Exception e) { - Log.e(LOG_TAG, "onLeaveGroup " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnGroupProfileUpdate(final String groupId) { - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onGroupProfileUpdate(groupId); - } catch (Exception e) { - Log.e(LOG_TAG, "onGroupProfileUpdate " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnGroupRoomsListUpdate(final String groupId) { - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onGroupRoomsListUpdate(groupId); - } catch (Exception e) { - Log.e(LOG_TAG, "onGroupRoomsListUpdate " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnGroupUsersListUpdate(final String groupId) { - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onGroupUsersListUpdate(groupId); - } catch (Exception e) { - Log.e(LOG_TAG, "onGroupUsersListUpdate " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnGroupInvitedUsersListUpdate(final String groupId) { - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onGroupInvitedUsersListUpdate(groupId); - } catch (Exception e) { - Log.e(LOG_TAG, "onGroupInvitedUsersListUpdate " + e.getMessage(), e); - } - } - } - }); - } - - public void dispatchOnNotificationCountUpdate(final String roomId, boolean ignoreEvent) { - if (ignoreEvent) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onNotificationCountUpdate(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onNotificationCountUpdate " + e.getMessage(), e); - } - } - } - }); - } - - /* ========================================================================================== - * Private - * ========================================================================================== */ - - /** - * @return the current MXEvents listeners. - */ - private List getListenersSnapshot() { - List eventListeners; - - synchronized (this) { - eventListeners = new ArrayList<>(mEventListeners); - } - - return eventListeners; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/RestClient.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/RestClient.java deleted file mode 100644 index 45759c85..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/RestClient.java +++ /dev/null @@ -1,414 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy; - -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.VisibleForTesting; -import android.text.TextUtils; -import android.util.Pair; - -import com.google.gson.Gson; - -import java.io.IOException; -import java.util.concurrent.TimeUnit; - -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.X509TrustManager; - -import im.vector.matrix.android.BuildConfig; -import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig; -import im.vector.matrix.android.api.auth.data.Credentials; -import im.vector.matrix.android.api.auth.data.SessionParams; -import im.vector.matrix.android.internal.legacy.listeners.IMXNetworkEventListener; -import im.vector.matrix.android.internal.legacy.network.NetworkConnectivityReceiver; -import im.vector.matrix.android.internal.legacy.rest.client.MXRestExecutorService; -import im.vector.matrix.android.internal.legacy.util.JsonUtils; -import im.vector.matrix.android.internal.legacy.util.PolymorphicRequestBodyConverter; -import im.vector.matrix.android.internal.legacy.util.UnsentEventsManager; -import im.vector.matrix.android.internal.network.ssl.CertUtil; -import okhttp3.Dispatcher; -import okhttp3.Interceptor; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import okhttp3.logging.HttpLoggingInterceptor; -import retrofit2.Retrofit; -import retrofit2.converter.gson.GsonConverterFactory; -import timber.log.Timber; - -/** - * Class for making Matrix API calls. - */ -public class RestClient { - - public static final String URI_API_PREFIX_PATH_MEDIA_R0 = "_matrix/media/r0/"; - public static final String URI_API_PREFIX_PATH_MEDIA_PROXY_UNSTABLE = "_matrix/media_proxy/unstable/"; - public static final String URI_API_PREFIX_PATH = "_matrix/client/"; - public static final String URI_API_PREFIX_PATH_R0 = "_matrix/client/r0/"; - public static final String URI_API_PREFIX_PATH_UNSTABLE = "_matrix/client/unstable/"; - - /** - * Prefix used in path of identity server API requests. - */ - public static final String URI_API_PREFIX_IDENTITY = "_matrix/identity/api/v1/"; - - /** - * List the servers which should be used to define the base url. - */ - public enum EndPointServer { - HOME_SERVER, - IDENTITY_SERVER, - ANTIVIRUS_SERVER - } - - protected static final int CONNECTION_TIMEOUT_MS = 30000; - private static final int READ_TIMEOUT_MS = 60000; - private static final int WRITE_TIMEOUT_MS = 60000; - - protected Credentials mCredentials; - - protected T mApi; - - protected Gson gson; - - protected UnsentEventsManager mUnsentEventsManager; - - protected HomeServerConnectionConfig mHsConfig; - - // unitary tests only - public static boolean mUseMXExecutor = false; - - // the user agent - private static String sUserAgent = null; - - // http client - private OkHttpClient mOkHttpClient = new OkHttpClient(); - - public RestClient(SessionParams sessionParams, Class type, String uriPrefix, boolean withNullSerialization) { - this(sessionParams, type, uriPrefix, withNullSerialization, EndPointServer.HOME_SERVER); - } - - /** - * Public constructor. - * - * @param sessionParams the session data - * @param type the REST type - * @param uriPrefix the URL request prefix - * @param withNullSerialization true to serialise class member with null value - * @param useIdentityServer true to use the identity server URL as base request - */ - public RestClient(SessionParams sessionParams, Class type, String uriPrefix, boolean withNullSerialization, boolean useIdentityServer) { - this(sessionParams, type, uriPrefix, withNullSerialization, useIdentityServer ? EndPointServer.IDENTITY_SERVER : EndPointServer.HOME_SERVER); - } - - /** - * Public constructor. - * - * @param sessionParams the session data - * @param type the REST type - * @param uriPrefix the URL request prefix - * @param withNullSerialization true to serialise class member with null value - * @param endPointServer tell which server is used to define the base url - */ - public RestClient(SessionParams sessionParams, Class type, String uriPrefix, boolean withNullSerialization, EndPointServer endPointServer) { - // The JSON -> object mapper - gson = JsonUtils.getGson(withNullSerialization); - mHsConfig = sessionParams.getHomeServerConnectionConfig(); - mCredentials = sessionParams.getCredentials(); - - Interceptor authentInterceptor = new Interceptor() { - - @Override - public Response intercept(Chain chain) throws IOException { - Request request = chain.request(); - Request.Builder newRequestBuilder = request.newBuilder(); - if (null != sUserAgent) { - // set a custom user agent - newRequestBuilder.addHeader("User-Agent", sUserAgent); - } - // Add the access token to all requests if it is set - if (mCredentials != null) { - newRequestBuilder.addHeader("Authorization", "Bearer " + mCredentials.getAccessToken()); - } - request = newRequestBuilder.build(); - - return chain.proceed(request); - } - }; - - // TODO Remove this, seems so useless - Interceptor connectivityInterceptor = new Interceptor() { - @Override - public Response intercept(Chain chain) throws IOException { - if (mUnsentEventsManager != null - && mUnsentEventsManager.getNetworkConnectivityReceiver() != null - && !mUnsentEventsManager.getNetworkConnectivityReceiver().isConnected()) { - throw new IOException("Not connected"); - } - return chain.proceed(chain.request()); - } - }; - - OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient().newBuilder() - .connectTimeout(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS) - .readTimeout(READ_TIMEOUT_MS, TimeUnit.MILLISECONDS) - .writeTimeout(WRITE_TIMEOUT_MS, TimeUnit.MILLISECONDS) - .addInterceptor(authentInterceptor) - .addInterceptor(connectivityInterceptor); - - if (BuildConfig.DEBUG) { - HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(); - loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BASIC); - okHttpClientBuilder - .addInterceptor(loggingInterceptor); - } - - - if (mUseMXExecutor) { - okHttpClientBuilder.dispatcher(new Dispatcher(new MXRestExecutorService())); - } - - try { - Pair pair = CertUtil.INSTANCE.newPinnedSSLSocketFactory(mHsConfig); - okHttpClientBuilder.sslSocketFactory(pair.first, pair.second); - okHttpClientBuilder.hostnameVerifier(CertUtil.INSTANCE.newHostnameVerifier(mHsConfig)); - okHttpClientBuilder.connectionSpecs(CertUtil.INSTANCE.newConnectionSpecs(mHsConfig)); - } catch (Exception e) { - Timber.e("## RestClient() setSslSocketFactory failed" + e.getMessage(), e); - } - mOkHttpClient = okHttpClientBuilder.build(); - final String endPoint = makeEndpoint(mHsConfig, uriPrefix, endPointServer); - // Rest adapter for turning API interfaces into actual REST-calling objects - Retrofit.Builder builder = new Retrofit.Builder() - .baseUrl(endPoint) - .addConverterFactory(PolymorphicRequestBodyConverter.FACTORY) - .addConverterFactory(GsonConverterFactory.create(gson)) - .client(mOkHttpClient); - - Retrofit retrofit = builder.build(); - - mApi = retrofit.create(type); - } - - @NonNull - private String makeEndpoint(HomeServerConnectionConfig hsConfig, String uriPrefix, EndPointServer endPointServer) { - String baseUrl; - switch (endPointServer) { - case IDENTITY_SERVER: - baseUrl = hsConfig.getIdentityServerUri().toString(); - break; - case ANTIVIRUS_SERVER: - baseUrl = hsConfig.getAntiVirusServerUri().toString(); - break; - case HOME_SERVER: - default: - baseUrl = hsConfig.getHomeServerUri().toString(); - - } - if (baseUrl == null) { - throw new IllegalArgumentException("Base url shouldn't be null"); - } - baseUrl = sanitizeBaseUrl(baseUrl); - String dynamicPath = sanitizeDynamicPath(uriPrefix); - return baseUrl + dynamicPath; - } - - private String sanitizeBaseUrl(String baseUrl) { - if (baseUrl.endsWith("/")) { - return baseUrl; - } - return baseUrl + "/"; - } - - private String sanitizeDynamicPath(String dynamicPath) { - // remove any trailing http in the uri prefix - if (dynamicPath.startsWith("http://")) { - dynamicPath = dynamicPath.substring("http://".length()); - } else if (dynamicPath.startsWith("https://")) { - dynamicPath = dynamicPath.substring("https://".length()); - } - return dynamicPath; - } - - /** - * Create an user agent with the application version. - * Ex: Riot/0.8.12 (Linux; U; Android 6.0.1; SM-A510F Build/MMB29; Flavour FDroid; MatrixAndroidSDK 0.9.6) - * - * @param appContext the application context - */ - public static void initUserAgent(Context appContext) { - String appName = ""; - String appVersion = ""; - - if (null != appContext) { - try { - PackageManager pm = appContext.getPackageManager(); - ApplicationInfo appInfo = pm.getApplicationInfo(appContext.getApplicationContext().getPackageName(), 0); - appName = pm.getApplicationLabel(appInfo).toString(); - - PackageInfo pkgInfo = pm.getPackageInfo(appContext.getApplicationContext().getPackageName(), 0); - appVersion = pkgInfo.versionName; - } catch (Exception e) { - Timber.e("## initUserAgent() : failed " + e.getMessage(), e); - } - } - - sUserAgent = System.getProperty("http.agent"); - - // cannot retrieve the application version - if (TextUtils.isEmpty(appName) || TextUtils.isEmpty(appVersion)) { - if (null == sUserAgent) { - sUserAgent = "Java" + System.getProperty("java.version"); - } - return; - } - - // if there is no user agent or cannot parse it - if ((null == sUserAgent) || (sUserAgent.lastIndexOf(")") == -1) || (sUserAgent.indexOf("(") == -1)) { - sUserAgent = appName + "/" + appVersion + "; MatrixAndroidSDK " + BuildConfig.VERSION_NAME + ")"; - } else { - // update - sUserAgent = appName + "/" + appVersion + " " + - sUserAgent.substring(sUserAgent.indexOf("("), sUserAgent.lastIndexOf(")") - 1) + - "; MatrixAndroidSDK " + BuildConfig.VERSION_NAME + ")"; - } - } - - /** - * Get the current user agent - * - * @return the current user agent, or null in case of error or if not initialized yet - */ - @Nullable - public static String getUserAgent() { - return sUserAgent; - } - - /** - * Refresh the connection timeouts. - * - * @param networkConnectivityReceiver the network connectivity receiver - */ - private void refreshConnectionTimeout(NetworkConnectivityReceiver networkConnectivityReceiver) { - OkHttpClient.Builder builder = mOkHttpClient.newBuilder(); - - if (networkConnectivityReceiver.isConnected()) { - float factor = networkConnectivityReceiver.getTimeoutScale(); - - builder - .connectTimeout((int) (CONNECTION_TIMEOUT_MS * factor), TimeUnit.MILLISECONDS) - .readTimeout((int) (READ_TIMEOUT_MS * factor), TimeUnit.MILLISECONDS) - .writeTimeout((int) (WRITE_TIMEOUT_MS * factor), TimeUnit.MILLISECONDS); - - Timber.d("## refreshConnectionTimeout() : update setConnectTimeout to " + (CONNECTION_TIMEOUT_MS * factor) + " ms"); - Timber.d("## refreshConnectionTimeout() : update setReadTimeout to " + (READ_TIMEOUT_MS * factor) + " ms"); - Timber.d("## refreshConnectionTimeout() : update setWriteTimeout to " + (WRITE_TIMEOUT_MS * factor) + " ms"); - } else { - builder.connectTimeout(1, TimeUnit.MILLISECONDS); - Timber.d("## refreshConnectionTimeout() : update the requests timeout to 1 ms"); - } - - // FIXME It has no effect to the rest client - mOkHttpClient = builder.build(); - } - - /** - * Update the connection timeout - * - * @param aTimeoutMs the connection timeout - */ - protected void setConnectionTimeout(int aTimeoutMs) { - int timeoutMs = aTimeoutMs; - - if (null != mUnsentEventsManager) { - NetworkConnectivityReceiver networkConnectivityReceiver = mUnsentEventsManager.getNetworkConnectivityReceiver(); - - if (null != networkConnectivityReceiver) { - if (networkConnectivityReceiver.isConnected()) { - timeoutMs *= networkConnectivityReceiver.getTimeoutScale(); - } else { - timeoutMs = 1000; - } - } - } - - if (timeoutMs != mOkHttpClient.connectTimeoutMillis()) { - // FIXME It has no effect to the rest client - mOkHttpClient = mOkHttpClient.newBuilder().connectTimeout(timeoutMs, TimeUnit.MILLISECONDS).build(); - } - } - - /** - * Set the unsentEvents manager. - * - * @param unsentEventsManager The unsentEvents manager. - */ - public void setUnsentEventsManager(UnsentEventsManager unsentEventsManager) { - mUnsentEventsManager = unsentEventsManager; - - final NetworkConnectivityReceiver networkConnectivityReceiver = mUnsentEventsManager.getNetworkConnectivityReceiver(); - refreshConnectionTimeout(networkConnectivityReceiver); - - networkConnectivityReceiver.addEventListener(new IMXNetworkEventListener() { - @Override - public void onNetworkConnectionUpdate(boolean isConnected) { - Timber.d("## setUnsentEventsManager() : update the requests timeout to " + (isConnected ? CONNECTION_TIMEOUT_MS : 1) + " ms"); - refreshConnectionTimeout(networkConnectivityReceiver); - } - }); - } - - /** - * Get the user's getCredentials. Typically for saving them somewhere persistent. - * - * @return the user getCredentials - */ - public Credentials getCredentials() { - return mCredentials; - } - - /** - * Provide the user's getCredentials. To be called after login or registration. - * - * @param credentials the user getCredentials - */ - public void setCredentials(Credentials credentials) { - mCredentials = credentials; - } - - /** - * Default protected constructor for unit tests. - */ - protected RestClient() { - } - - /** - * Protected setter for injection by unit tests. - * - * @param api the api object - */ - @VisibleForTesting() - protected void setApi(T api) { - mApi = api; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/CallSoundsManager.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/CallSoundsManager.java deleted file mode 100644 index 9f93f54c..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/CallSoundsManager.java +++ /dev/null @@ -1,797 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.call; - -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.media.AudioManager; -import android.media.MediaPlayer; -import android.media.Ringtone; -import android.media.RingtoneManager; -import android.net.Uri; -import android.os.Environment; -import android.os.Vibrator; -import android.provider.MediaStore; - -import im.vector.matrix.android.R; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -/** - * This class manages the call sound. - * It is in charge of playing ring tones and managing the audio focus. - */ -public class CallSoundsManager { - private static final String LOG_TAG = CallSoundsManager.class.getSimpleName(); - - /** - * Track the audio focus update. - */ - public interface OnAudioFocusListener { - /** - * Call back indicating new focus events (ex: {@link AudioManager#AUDIOFOCUS_GAIN}, - * {@link AudioManager#AUDIOFOCUS_LOSS}..). - * - * @param aFocusEvent the focus event (see {@link AudioManager.OnAudioFocusChangeListener}) - */ - void onFocusChanged(int aFocusEvent); - } - - /** - * Track the audio configuration change (like speaker, micro and so on). - */ - public interface OnAudioConfigurationUpdateListener { - void onAudioConfigurationUpdate(); - } - - /** - * Track the media statuses. - */ - public interface OnMediaListener { - - /** - * The media is ready to be played - */ - void onMediaReadyToPlay(); - - /** - * The media is playing. - */ - void onMediaPlay(); - - /** - * The media has been played - */ - void onMediaCompleted(); - } - - private static CallSoundsManager mSharedInstance = null; - private final Context mContext; - - /** - * Constructor - * - * @param context the context - */ - private CallSoundsManager(Context context) { - mContext = context; - } - - /** - * Provides the shared instance. - * - * @param context the context - * @return the shared instance - */ - public static CallSoundsManager getSharedInstance(Context context) { - if (null == mSharedInstance) { - mSharedInstance = new CallSoundsManager(context.getApplicationContext()); - } - - return mSharedInstance; - } - - //============================================================================================================== - // Audio configuration management - //============================================================================================================== - // audio focus management - private final Set mOnAudioConfigurationUpdateListener = new HashSet<>(); - - /** - * Add an audio configuration update listener. - * - * @param listener the listener. - */ - public void addAudioConfigurationListener(OnAudioConfigurationUpdateListener listener) { - synchronized (LOG_TAG) { - mOnAudioConfigurationUpdateListener.add(listener); - } - } - - /** - * Remove an audio configuration update listener. - * - * @param listener the listener. - */ - public void removeAudioConfigurationListener(OnAudioConfigurationUpdateListener listener) { - synchronized (LOG_TAG) { - mOnAudioConfigurationUpdateListener.remove(listener); - } - } - - /** - * Dispatch that the audio configuration has been updated. - */ - private void dispatchAudioConfigurationUpdate() { - synchronized (LOG_TAG) { - // notify listeners - for (OnAudioConfigurationUpdateListener listener : mOnAudioConfigurationUpdateListener) { - try { - listener.onAudioConfigurationUpdate(); - } catch (Exception e) { - Log.e(LOG_TAG, "## dispatchAudioConfigurationUpdate() failed " + e.getMessage(), e); - } - } - } - } - - //============================================================================================================== - // Focus management - //============================================================================================================== - - // audio focus management - private final Set mAudioFocusListeners = new HashSet<>(); - - private final AudioManager.OnAudioFocusChangeListener mFocusListener = new AudioManager.OnAudioFocusChangeListener() { - @Override - public void onAudioFocusChange(int aFocusEvent) { - switch (aFocusEvent) { - case AudioManager.AUDIOFOCUS_GAIN: - Log.d(LOG_TAG, "## OnAudioFocusChangeListener(): AUDIOFOCUS_GAIN"); - // TODO resume voip call (ex: ending GSM call) - break; - - case AudioManager.AUDIOFOCUS_LOSS: - Log.d(LOG_TAG, "## OnAudioFocusChangeListener(): AUDIOFOCUS_LOSS"); - // TODO pause voip call (ex: incoming GSM call) - break; - - case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT: - Log.d(LOG_TAG, "## OnAudioFocusChangeListener(): AUDIOFOCUS_GAIN_TRANSIENT"); - break; - - case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: - Log.d(LOG_TAG, "## OnAudioFocusChangeListener(): AUDIOFOCUS_LOSS_TRANSIENT"); - // TODO pause voip call (ex: incoming GSM call) - break; - - case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: - // TODO : continue playing at an attenuated level - Log.d(LOG_TAG, "## OnAudioFocusChangeListener(): AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK"); - break; - - case AudioManager.AUDIOFOCUS_REQUEST_FAILED: - Log.d(LOG_TAG, "## OnAudioFocusChangeListener(): AUDIOFOCUS_REQUEST_FAILED"); - break; - - default: - break; - } - - synchronized (LOG_TAG) { - // notify listeners - for (OnAudioFocusListener listener : mAudioFocusListeners) { - try { - listener.onFocusChanged(aFocusEvent); - } catch (Exception e) { - Log.e(LOG_TAG, "## onFocusChanged() failed " + e.getMessage(), e); - } - } - } - } - }; - - /** - * Add a focus listener. - * - * @param focusListener the listener. - */ - public void addFocusListener(OnAudioFocusListener focusListener) { - synchronized (LOG_TAG) { - mAudioFocusListeners.add(focusListener); - } - } - - /** - * Remove a focus listener. - * - * @param focusListener the listener. - */ - public void removeFocusListener(OnAudioFocusListener focusListener) { - synchronized (LOG_TAG) { - mAudioFocusListeners.remove(focusListener); - } - } - - //============================================================================================================== - // Ringtone management management - //============================================================================================================== - - /** - * @return the audio manager - */ - private AudioManager getAudioManager() { - if (null == mAudioManager) { - mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); - } - - return mAudioManager; - } - - // audio focus - private boolean mIsFocusGranted = false; - - private static final int VIBRATE_DURATION = 500; // milliseconds - private static final int VIBRATE_SLEEP = 1000; // milliseconds - private static final long[] VIBRATE_PATTERN = {0, VIBRATE_DURATION, VIBRATE_SLEEP}; - - private Ringtone mRingTone; - private boolean mIsRinging; - private MediaPlayer mMediaPlayer = null; - - // the audio manager (do not use directly, use getAudioManager()) - private AudioManager mAudioManager = null; - - // the playing sound - private int mPlayingSound = -1; - - /** - * Tells that the device is ringing. - * - * @return true if the device is ringing - */ - public boolean isRinging() { - return mIsRinging; - } - - /** - * Getter method. - * - * @return true is focus is granted, false otherwise. - */ - public boolean isFocusGranted() { - return mIsFocusGranted; - } - - /** - * Stop any playing sound. - */ - public void stopSounds() { - mIsRinging = false; - - if (null != mRingTone) { - mRingTone.stop(); - mRingTone = null; - } - - if (null != mMediaPlayer) { - if (mMediaPlayer.isPlaying()) { - mMediaPlayer.stop(); - } - - mMediaPlayer.release(); - mMediaPlayer = null; - } - - mPlayingSound = -1; - - // stop vibrate - enableVibrating(false); - } - - /** - * Stop the ringing sound - */ - public void stopRinging() { - Log.d(LOG_TAG, "stopRinging"); - stopSounds(); - - // stop vibrate - enableVibrating(false); - } - - /** - * Request a permanent audio focus if the focus was not yet granted. - */ - public void requestAudioFocus() { - if (!mIsFocusGranted) { - int focusResult; - AudioManager audioMgr; - - if ((null != (audioMgr = getAudioManager()))) { - // Request permanent audio focus for voice call - focusResult = audioMgr.requestAudioFocus(mFocusListener, AudioManager.STREAM_VOICE_CALL, AudioManager.AUDIOFOCUS_GAIN); - - if (AudioManager.AUDIOFOCUS_REQUEST_GRANTED == focusResult) { - mIsFocusGranted = true; - Log.d(LOG_TAG, "## getAudioFocus(): granted"); - } else { - mIsFocusGranted = false; - Log.w(LOG_TAG, "## getAudioFocus(): refused - focusResult=" + focusResult); - } - } - - dispatchAudioConfigurationUpdate(); - } else { - Log.d(LOG_TAG, "## getAudioFocus(): already granted"); - } - } - - /** - * Release the audio focus if it was granted. - */ - public void releaseAudioFocus() { - if (mIsFocusGranted) { - AudioManager audioManager = getAudioManager(); - - if ((null != audioManager)) { - // release focus - int abandonResult = audioManager.abandonAudioFocus(mFocusListener); - - if (AudioManager.AUDIOFOCUS_REQUEST_GRANTED == abandonResult) { - Log.d(LOG_TAG, "## releaseAudioFocus(): abandonAudioFocus = AUDIOFOCUS_REQUEST_GRANTED"); - } - - if (AudioManager.AUDIOFOCUS_REQUEST_FAILED == abandonResult) { - Log.d(LOG_TAG, "## releaseAudioFocus(): abandonAudioFocus = AUDIOFOCUS_REQUEST_FAILED"); - } - } else { - Log.d(LOG_TAG, "## releaseAudioFocus(): failure - invalid AudioManager"); - } - - mIsFocusGranted = false; - } - - restoreAudioConfig(); - dispatchAudioConfigurationUpdate(); - } - - /** - * Start the ringing sound. - * - * @param resId the ring sound id - * @param filename the filename to save the ringtone - */ - public void startRinging(int resId, String filename) { - Log.v(LOG_TAG, "startRinging"); - if (mRingTone != null) { - Log.v(LOG_TAG, "ring tone already ringing"); - } - // stop any playing ringtone - stopSounds(); - mIsRinging = true; - // use the ringTone to manage sound volume properly - mRingTone = getRingTone(mContext, resId, filename, RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE)); - if (mRingTone != null) { - setSpeakerphoneOn(false, true); - mRingTone.play(); - } else { - Log.e(LOG_TAG, "startRinging : fail to retrieve RING_TONE_START_RINGING"); - } - // start vibrate - enableVibrating(true); - } - - /** - * Same than {@link #startRinging(int, String)}}, but do not play sound, nor vibrate. - */ - public void startRingingSilently() { - mIsRinging = true; - } - - /** - * Enable the vibrate mode. - * - * @param aIsVibrateEnabled true to force vibrate, false to stop vibrate. - */ - private void enableVibrating(boolean aIsVibrateEnabled) { - Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE); - - if ((null != vibrator) && vibrator.hasVibrator()) { - if (aIsVibrateEnabled) { - vibrator.vibrate(VIBRATE_PATTERN, 0 /*repeat till stop*/); - Log.d(LOG_TAG, "## startVibrating(): Vibrate started"); - } else { - vibrator.cancel(); - Log.d(LOG_TAG, "## startVibrating(): Vibrate canceled"); - } - } else { - Log.w(LOG_TAG, "## startVibrating(): vibrator access failed"); - } - } - - /** - * Start a sound. - * - * @param resId the sound resource id - * @param isLooping true to loop - * @param listener the listener - */ - public void startSound(int resId, boolean isLooping, final OnMediaListener listener) { - Log.d(LOG_TAG, "startSound"); - - if (mPlayingSound == resId) { - Log.d(LOG_TAG, "## startSound() : already playing " + resId); - return; - } - - stopSounds(); - mPlayingSound = resId; - - mMediaPlayer = MediaPlayer.create(mContext, resId); - - if (null != mMediaPlayer) { - mMediaPlayer.setLooping(isLooping); - - if (null != listener) { - listener.onMediaReadyToPlay(); - } - - mMediaPlayer.start(); - - if (null != listener) { - listener.onMediaPlay(); - } - - mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { - @Override - public void onCompletion(MediaPlayer mp) { - if (null != listener) { - listener.onMediaCompleted(); - } - mPlayingSound = -1; - - if (null != mMediaPlayer) { - mMediaPlayer.release(); - mMediaPlayer = null; - } - } - }); - - } else { - Log.e(LOG_TAG, "startSound : failed"); - } - } - - //============================================================================================================== - // resid / filenime to ringtone - //============================================================================================================== - - private static final Map mRingtoneUrlByFileName = new HashMap<>(); - - /** - * Provide a ringtone uri from a resource and a filename. - * - * @param context the context - * @param resId The audio resource. - * @param filename the audio filename - * @return the ringtone uri - */ - private static Uri getRingToneUri(Context context, int resId, String filename) { - Uri ringToneUri = mRingtoneUrlByFileName.get(filename); - // test if the ring tone has been cached - - if (null != ringToneUri) { - // check if the file exists - try { - File ringFile = new File(ringToneUri.toString()); - - // check if the file exists - if ((null != ringFile) && ringFile.exists() && ringFile.canRead()) { - // provide it - return ringToneUri; - } - } catch (Exception e) { - Log.e(LOG_TAG, "## getRingToneUri() failed " + e.getMessage(), e); - } - } - - try { - File directory = new File(Environment.getExternalStorageDirectory(), "/" + context.getApplicationContext().getPackageName().hashCode() + "/Audio/"); - - // create the directory if it does not exist - if (!directory.exists()) { - directory.mkdirs(); - } - - File file = new File(directory + "/", filename); - - // if the file exists, check if the resource has been created - if (file.exists()) { - Cursor cursor = context.getContentResolver().query( - MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, - new String[]{MediaStore.Audio.Media._ID}, - MediaStore.Audio.Media.DATA + "=? ", - new String[]{file.getAbsolutePath()}, null); - - if ((null != cursor) && cursor.moveToFirst()) { - int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID)); - ringToneUri = Uri.withAppendedPath(Uri.parse("content://media/external/audio/media"), "" + id); - } - - if (null != cursor) { - cursor.close(); - } - } - - // the Uri has been retrieved - if (null == ringToneUri) { - // create the file - if (!file.exists()) { - try { - byte[] readData = new byte[1024]; - InputStream fis = context.getResources().openRawResource(resId); - FileOutputStream fos = new FileOutputStream(file); - int i = fis.read(readData); - - while (i != -1) { - fos.write(readData, 0, i); - i = fis.read(readData); - } - - fos.close(); - } catch (Exception e) { - Log.e(LOG_TAG, "## getRingToneUri(): Exception1 Msg=" + e.getMessage(), e); - } - } - - // and the resource Uri - ContentValues values = new ContentValues(); - values.put(MediaStore.MediaColumns.DATA, file.getAbsolutePath()); - values.put(MediaStore.MediaColumns.TITLE, filename); - values.put(MediaStore.MediaColumns.MIME_TYPE, "audio/ogg"); - values.put(MediaStore.MediaColumns.SIZE, file.length()); - values.put(MediaStore.Audio.Media.ARTIST, R.string.app_name); - values.put(MediaStore.Audio.Media.IS_RINGTONE, true); - values.put(MediaStore.Audio.Media.IS_NOTIFICATION, true); - values.put(MediaStore.Audio.Media.IS_ALARM, true); - values.put(MediaStore.Audio.Media.IS_MUSIC, true); - - ringToneUri = context.getContentResolver().insert(MediaStore.Audio.Media.getContentUriForPath(file.getAbsolutePath()), values); - } - - if (null != ringToneUri) { - mRingtoneUrlByFileName.put(filename, ringToneUri); - return ringToneUri; - } - } catch (Exception e) { - Log.e(LOG_TAG, "## getRingToneUri(): Exception2 Msg=" + e.getLocalizedMessage(), e); - } - - return null; - } - - /** - * Retrieve a ringtone from an uri - * - * @param context the context - * @param ringToneUri the ringtone URI - * @return the ringtone - */ - private static Ringtone uriToRingTone(Context context, Uri ringToneUri) { - if (null != ringToneUri) { - try { - return RingtoneManager.getRingtone(context, ringToneUri); - } catch (Exception e) { - Log.e(LOG_TAG, "## uriToRingTone() failed " + e.getMessage(), e); - } - } - - return null; - } - - /** - * Provide a ringtone from a resource and a filename. - * The audio file must have a ANDROID_LOOP metatada set to true to loop the sound. - * - * @param context the context - * @param resId The audio resource. - * @param filename the audio filename - * @param defaultRingToneUri the default ring tone - * @return a RingTone, null if the operation fails. - */ - private static Ringtone getRingTone(Context context, int resId, String filename, Uri defaultRingToneUri) { - Ringtone ringtone = uriToRingTone(context, getRingToneUri(context, resId, filename)); - - if (null == ringtone) { - ringtone = uriToRingTone(context, defaultRingToneUri); - } - - Log.d(LOG_TAG, "getRingTone() : resId " + resId + " filename " + filename + " defaultRingToneUri " + defaultRingToneUri + " returns " + ringtone); - - return ringtone; - } - - //============================================================================================================== - // speakers management - //============================================================================================================== - - // save the audio statuses - private Integer mAudioMode = null; - private Boolean mIsSpeakerphoneOn = null; - - /** - * Back up the current audio config. - */ - private void backupAudioConfig() { - if (null == mAudioMode) { - AudioManager audioManager = getAudioManager(); - - mAudioMode = audioManager.getMode(); - mIsSpeakerphoneOn = audioManager.isSpeakerphoneOn(); - } - } - - /** - * Restore the audio config. - */ - private void restoreAudioConfig() { - // ensure that something has been saved - if ((null != mAudioMode) && (null != mIsSpeakerphoneOn)) { - Log.d(LOG_TAG, "## restoreAudioConfig() starts"); - AudioManager audioManager = getAudioManager(); - - if (mAudioMode != audioManager.getMode()) { - Log.d(LOG_TAG, "## restoreAudioConfig() : restore audio mode " + mAudioMode); - audioManager.setMode(mAudioMode); - } - - if (mIsSpeakerphoneOn != audioManager.isSpeakerphoneOn()) { - Log.d(LOG_TAG, "## restoreAudioConfig() : restore speaker " + mIsSpeakerphoneOn); - audioManager.setSpeakerphoneOn(mIsSpeakerphoneOn); - } - - // stop the bluetooth - if (audioManager.isBluetoothScoOn()) { - Log.d(LOG_TAG, "## restoreAudioConfig() : ends the bluetooth calls"); - audioManager.stopBluetoothSco(); - audioManager.setBluetoothScoOn(false); - } - - mAudioMode = null; - mIsSpeakerphoneOn = null; - - Log.d(LOG_TAG, "## restoreAudioConfig() done"); - } - } - - /** - * Set the speakerphone ON or OFF. - * - * @param isOn true to enable the speaker (ON), false to disable it (OFF) - */ - public void setCallSpeakerphoneOn(boolean isOn) { - setSpeakerphoneOn(true, isOn); - } - - /** - * Save the current speaker status and the audio mode, before updating those - * values. - * The audio mode depends on if there is a call in progress. - * If audio mode set to {@link AudioManager#MODE_IN_COMMUNICATION} and - * a media player is in ON, the media player will reduce its audio level. - * - * @param isInCall true when the speaker is updated during call. - * @param isSpeakerOn true to turn on the speaker (false to turn it off) - */ - public void setSpeakerphoneOn(boolean isInCall, boolean isSpeakerOn) { - Log.d(LOG_TAG, "setCallSpeakerphoneOn " + isSpeakerOn); - - backupAudioConfig(); - - try { - AudioManager audioManager = getAudioManager(); - - int audioMode = isInCall ? AudioManager.MODE_IN_COMMUNICATION : AudioManager.MODE_RINGTONE; - - if (audioManager.getMode() != audioMode) { - audioManager.setMode(audioMode); - } - - if (!isSpeakerOn) { - try { - if (HeadsetConnectionReceiver.isBTHeadsetPlugged()) { - audioManager.startBluetoothSco(); - audioManager.setBluetoothScoOn(true); - } else if (audioManager.isBluetoothScoOn()) { - audioManager.stopBluetoothSco(); - audioManager.setBluetoothScoOn(false); - } - } catch (Exception e) { - Log.e(LOG_TAG, "## setSpeakerphoneOn() failed " + e.getMessage(), e); - } - } - - if (isSpeakerOn != audioManager.isSpeakerphoneOn()) { - audioManager.setSpeakerphoneOn(isSpeakerOn); - } - } catch (Exception e) { - Log.e(LOG_TAG, "## setSpeakerphoneOn() failed " + e.getMessage(), e); - restoreAudioConfig(); - } - - dispatchAudioConfigurationUpdate(); - } - - /** - * Toggle the speaker - */ - public void toggleSpeaker() { - AudioManager audioManager = getAudioManager(); - boolean isOn = !audioManager.isSpeakerphoneOn(); - audioManager.setSpeakerphoneOn(isOn); - - if (!isOn) { - try { - if (HeadsetConnectionReceiver.isBTHeadsetPlugged()) { - audioManager.startBluetoothSco(); - audioManager.setBluetoothScoOn(true); - } else if (audioManager.isBluetoothScoOn()) { - audioManager.stopBluetoothSco(); - audioManager.setBluetoothScoOn(false); - } - } catch (Exception e) { - Log.e(LOG_TAG, "## toggleSpeaker() failed " + e.getMessage(), e); - } - } - - dispatchAudioConfigurationUpdate(); - } - - /** - * @return true if the speaker is turned on. - */ - public boolean isSpeakerphoneOn() { - return getAudioManager().isSpeakerphoneOn(); - } - - /** - * Mute the microphone. - * - * @param mute true to mute the microphone - */ - public void setMicrophoneMute(boolean mute) { - getAudioManager().setMicrophoneMute(mute); - dispatchAudioConfigurationUpdate(); - } - - /** - * @return true if the microphone is mute. - */ - public boolean isMicrophoneMute() { - return getAudioManager().isMicrophoneMute(); - } -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/HeadsetConnectionReceiver.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/HeadsetConnectionReceiver.java deleted file mode 100644 index 3d33ddd2..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/HeadsetConnectionReceiver.java +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.call; - -import android.annotation.SuppressLint; -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothProfile; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.media.AudioManager; -import android.os.Handler; -import android.os.Looper; -import android.text.TextUtils; - -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.util.HashSet; -import java.util.Set; - -// this class detect if the headset is plugged / unplugged -public class HeadsetConnectionReceiver extends BroadcastReceiver { - - private static final String LOG_TAG = HeadsetConnectionReceiver.class.getSimpleName(); - - private static Boolean mIsHeadsetPlugged = null; - - private static HeadsetConnectionReceiver mSharedInstance = null; - - /** - * Track the headset update. - */ - public interface OnHeadsetStatusUpdateListener { - /** - * A wire headset has been plugged / unplugged. - * - * @param isPlugged true if the headset is now plugged. - */ - void onWiredHeadsetUpdate(boolean isPlugged); - - /** - * A bluetooth headset is connected. - * - * @param isConnected true if the bluetooth headset is connected. - */ - void onBluetoothHeadsetUpdate(boolean isConnected); - - } - - // listeners - private final Set mListeners = new HashSet<>(); - - public HeadsetConnectionReceiver() { - } - - /** - * @param context the application context - * @return the shared instance - */ - public static HeadsetConnectionReceiver getSharedInstance(Context context) { - if (null == mSharedInstance) { - mSharedInstance = new HeadsetConnectionReceiver(); - context.registerReceiver(mSharedInstance, new IntentFilter(Intent.ACTION_HEADSET_PLUG)); - context.registerReceiver(mSharedInstance, new IntentFilter(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)); - context.registerReceiver(mSharedInstance, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)); - context.registerReceiver(mSharedInstance, new IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED)); - context.registerReceiver(mSharedInstance, new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED)); - } - - return mSharedInstance; - } - - /** - * Add a listener. - * - * @param listener the listener to add. - */ - public void addListener(OnHeadsetStatusUpdateListener listener) { - synchronized (LOG_TAG) { - mListeners.add(listener); - } - } - - /** - * Remove a listener. - * - * @param listener the listener to remove. - */ - public void removeListener(OnHeadsetStatusUpdateListener listener) { - synchronized (LOG_TAG) { - mListeners.remove(listener); - } - } - - /** - * Dispatch onBluetoothHeadsetUpdate to the listeners. - * - * @param isConnected true if a bluetooth headset is connected. - */ - private void onBluetoothHeadsetUpdate(boolean isConnected) { - synchronized (LOG_TAG) { - for (OnHeadsetStatusUpdateListener listener : mListeners) { - try { - listener.onBluetoothHeadsetUpdate(isConnected); - } catch (Exception e) { - Log.e(LOG_TAG, "## onBluetoothHeadsetUpdate()) failed " + e.getMessage(), e); - } - } - } - } - - /** - * Dispatch onWireHeadsetUpdate to the listeners. - * - * @param isPlugged true if the wire headset is plugged. - */ - private void onWiredHeadsetUpdate(boolean isPlugged) { - synchronized (LOG_TAG) { - for (OnHeadsetStatusUpdateListener listener : mListeners) { - try { - listener.onWiredHeadsetUpdate(isPlugged); - } catch (Exception e) { - Log.e(LOG_TAG, "## onWiredHeadsetUpdate()) failed " + e.getMessage(), e); - } - } - } - } - - @Override - public void onReceive(final Context aContext, final Intent aIntent) { - Log.d(LOG_TAG, "## onReceive() : " + aIntent.getExtras()); - String action = aIntent.getAction(); - - if (TextUtils.equals(action, Intent.ACTION_HEADSET_PLUG) - || TextUtils.equals(action, BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED) - || TextUtils.equals(action, BluetoothAdapter.ACTION_STATE_CHANGED) - || TextUtils.equals(action, BluetoothDevice.ACTION_ACL_CONNECTED) - || TextUtils.equals(action, BluetoothDevice.ACTION_ACL_DISCONNECTED)) { - - Boolean newState = null; - final boolean isBTHeadsetUpdate; - - if (TextUtils.equals(action, Intent.ACTION_HEADSET_PLUG)) { - int state = aIntent.getIntExtra("state", -1); - - switch (state) { - case 0: - Log.d(LOG_TAG, "Headset is unplugged"); - newState = false; - break; - case 1: - Log.d(LOG_TAG, "Headset is plugged"); - newState = true; - break; - default: - Log.d(LOG_TAG, "undefined state"); - } - isBTHeadsetUpdate = false; - } else { - int state = BluetoothAdapter.getDefaultAdapter().getProfileConnectionState(BluetoothProfile.HEADSET); - - Log.d(LOG_TAG, "bluetooth headset state " + state); - newState = (BluetoothAdapter.STATE_CONNECTED == state); - isBTHeadsetUpdate = mIsHeadsetPlugged != newState; - } - - if (newState != mIsHeadsetPlugged) { - mIsHeadsetPlugged = newState; - - // wait a little else route to BT headset does not work. - new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { - @Override - public void run() { - if (isBTHeadsetUpdate) { - onBluetoothHeadsetUpdate(mIsHeadsetPlugged); - } else { - onWiredHeadsetUpdate(mIsHeadsetPlugged); - } - } - }, 1000); - } - } - } - - private static AudioManager mAudioManager = null; - - /** - * @return the audio manager - */ - private static AudioManager getAudioManager(Context context) { - if (null == mAudioManager) { - mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - } - - return mAudioManager; - } - - - /** - * @param context the context - * @return true if the headset is plugged - */ - @SuppressLint("Deprecation") - public static boolean isHeadsetPlugged(Context context) { - if (null == mIsHeadsetPlugged) { - AudioManager audioManager = getAudioManager(context); - mIsHeadsetPlugged = isBTHeadsetPlugged() || audioManager.isWiredHeadsetOn(); - } - - return mIsHeadsetPlugged; - } - - /** - * @return true if bluetooth headset is plugged - */ - public static boolean isBTHeadsetPlugged() { - return (BluetoothAdapter.STATE_CONNECTED == BluetoothAdapter.getDefaultAdapter().getProfileConnectionState(BluetoothProfile.HEADSET)); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/IMXCall.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/IMXCall.java deleted file mode 100644 index a0a2c419..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/IMXCall.java +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Copyright 2015 OpenMarket 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.matrix.android.internal.legacy.call; - -import android.view.View; - -import com.google.gson.JsonObject; - -import im.vector.matrix.android.internal.legacy.MXSession; -import im.vector.matrix.android.internal.legacy.data.Room; -import im.vector.matrix.android.internal.legacy.rest.model.Event; - -/** - * Audio/video call interface. - * See {@link MXWebRtcCall} and {@link MXChromeCall}. - */ -public interface IMXCall { - - // call ending use cases (see {@link #dispatchOnCallEnd}): - int END_CALL_REASON_UNDEFINED = -1; - /** - * the callee has rejected the incoming call - **/ - int END_CALL_REASON_PEER_HANG_UP = 0; - /** - * the callee has rejected the incoming call from another device - **/ - int END_CALL_REASON_PEER_HANG_UP_ELSEWHERE = 1; - /** - * call ended by the local user himself - **/ - int END_CALL_REASON_USER_HIMSELF = 2; - - // call state events - - // the call is an empty shell nothing has been initialized - String CALL_STATE_CREATED = "IMXCall.CALL_STATE_CREATED"; - - // the call view is creating and being inserting. - String CALL_STATE_CREATING_CALL_VIEW = "IMXCall.CALL_STATE_CREATING_CALL_VIEW"; - - // the call view is managed. - // the call can start from now. - String CALL_STATE_READY = "IMXCall.CALL_STATE_READY"; - - // incoming/outgoing calls : initializing the local audio / video - String CALL_STATE_WAIT_LOCAL_MEDIA = "IMXCall.CALL_STATE_WAIT_LOCAL_MEDIA"; - - // incoming calls : the local media is retrieved - String CALL_STATE_WAIT_CREATE_OFFER = "IMXCall.CALL_STATE_WAIT_CREATE_OFFER"; - - // outgoing calls : the call invitation is sent - String CALL_STATE_INVITE_SENT = "IMXCall.CALL_STATE_INVITE_SENT"; - - // the device is ringing - // incoming calls : after applying the incoming params - // outgoing calls : after getting the m.call.invite echo - String CALL_STATE_RINGING = "IMXCall.CALL_STATE_RINGING"; - - // incoming calls : create the call answer - String CALL_STATE_CREATE_ANSWER = "IMXCall.CALL_STATE_CREATE_ANSWER"; - - // the call is connecting - String CALL_STATE_CONNECTING = "IMXCall.CALL_STATE_CONNECTING"; - - // the call is in progress - String CALL_STATE_CONNECTED = "IMXCall.CALL_STATE_CONNECTED"; - - // call is ended - String CALL_STATE_ENDED = "IMXCall.CALL_STATE_ENDED"; - - // error codes - // cannot initialize the camera - String CALL_ERROR_CAMERA_INIT_FAILED = "IMXCall.CALL_ERROR_CAMERA_INIT_FAILED"; - - // cannot initialize the call. - String CALL_ERROR_CALL_INIT_FAILED = "IMXCall.CALL_ERROR_CALL_INIT_FAILED"; - - // ICE error - String CALL_ERROR_ICE_FAILED = "IMXCall.CALL_ERROR_ICE_FAILED"; - - // the user did not respond to the call. - String CALL_ERROR_USER_NOT_RESPONDING = "IMXCall.CALL_ERROR_USER_NOT_RESPONDING"; - - // creator - - /** - * Create the callview - */ - void createCallView(); - - /** - * The activity is paused. - */ - void onPause(); - - /** - * The activity is resumed. - */ - void onResume(); - - // actions (must be done after dispatchOnViewReady() - - /** - * Start a call. - * - * @param aLocalVideoPosition position of the local video attendee - */ - void placeCall(VideoLayoutConfiguration aLocalVideoPosition); - - /** - * Prepare a call reception. - * - * @param aCallInviteParams the invitation Event content - * @param aCallId the call ID - * @param aLocalVideoPosition position of the local video attendee - */ - void prepareIncomingCall(JsonObject aCallInviteParams, String aCallId, VideoLayoutConfiguration aLocalVideoPosition); - - /** - * The call has been detected as an incoming one. - * The application launched the dedicated activity and expects to launch the incoming call. - * - * @param aLocalVideoPosition position of the local video attendee - */ - void launchIncomingCall(VideoLayoutConfiguration aLocalVideoPosition); - - /** - * The video will be displayed according to the values set in aConfigurationToApply. - * - * @param aConfigurationToApply the new position to be applied - */ - void updateLocalVideoRendererPosition(VideoLayoutConfiguration aConfigurationToApply); - - // events thread - - /** - * Manage the call events. - * - * @param event the call event. - */ - void handleCallEvent(Event event); - - // user actions - - /** - * The call is accepted. - */ - void answer(); - - /** - * The call has been has answered on another device. - */ - void onAnsweredElsewhere(); - - /** - * The call is hung up. - * - * @param reason the reason - */ - void hangup(String reason); - - /** - * Add a listener to the call manager. - * - * @param callListener the call listener - */ - void addListener(IMXCallListener callListener); - - /** - * Remove a listener from the call manager. - * - * @param callListener the call listener - */ - void removeListener(IMXCallListener callListener); - - // getters / setters - - /** - * @return the callId - */ - String getCallId(); - - /** - * Set the callId - * - * @param callId the call id - */ - void setCallId(String callId); - - /** - * @return the linked room - */ - Room getRoom(); - - /** - * Set the linked rooms (conference call) - * - * @param room the room - * @param callSignalingRoom the call signaling room. - */ - void setRooms(Room room, Room callSignalingRoom); - - /** - * @return the call signaling room - */ - Room getCallSignalingRoom(); - - /** - * @return the session - */ - MXSession getSession(); - - /** - * @return true if the call is an incoming call. - */ - boolean isIncoming(); - - /** - * Set the call type: video or voice - * - * @param isVideo true for video call, false for VoIP - */ - void setIsVideo(boolean isVideo); - - /** - * @return true if the call is a video call. - */ - boolean isVideo(); - - /** - * Defines the call conference status - * - * @param isConference the conference status - */ - void setIsConference(boolean isConference); - - /** - * @return true if the call is a conference call. - */ - boolean isConference(); - - /** - * @return the callstate (must be a CALL_STATE_XX value) - */ - String getCallState(); - - /** - * @return the callView - */ - View getCallView(); - - /** - * @return the callView visibility - */ - int getVisibility(); - - /** - * Set the callview visibility - * - * @param visibility true to make the callview visible - * @return true if the operation succeeds - */ - boolean setVisibility(int visibility); - - /** - * @return the call start time in ms since epoch, -1 if not defined. - */ - long getCallStartTime(); - - /** - * @return the call elapsed time in seconds, -1 if not defined. - */ - long getCallElapsedTime(); - - /** - * Switch between device cameras. The transmitted stream is modified - * according to the new camera in use. - * If the camera used in the video call is the front one, calling - * switchRearFrontCamera(), will make the rear one to be used, and vice versa. - * If only one camera is available, nothing is done. - * - * @return true if the switch succeed, false otherwise. - */ - boolean switchRearFrontCamera(); - - /** - * Indicate if a camera switch was performed or not. - * For some reason switching the camera from front to rear and - * vice versa, could not be performed (ie. only one camera is available). - *

- *
See {@link #switchRearFrontCamera()}. - * - * @return true if camera was switched, false otherwise - */ - boolean isCameraSwitched(); - - /** - * Indicate if the device supports camera switching. - *

See {@link #switchRearFrontCamera()}. - * - * @return true if switch camera is supported, false otherwise - */ - boolean isSwitchCameraSupported(); - - /** - * Mute/Unmute the recording of the local video attendee. Set isVideoMuted - * to true to enable the recording of the video, if set to false no recording - * is performed. - * - * @param isVideoMuted true to mute the video recording, false to unmute - */ - void muteVideoRecording(boolean isVideoMuted); - - /** - * Return the recording mute status of the local video attendee. - *

- *
See {@link #muteVideoRecording(boolean)}. - * - * @return true if video recording is muted, false otherwise - */ - boolean isVideoRecordingMuted(); -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/IMXCallListener.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/IMXCallListener.java deleted file mode 100644 index fd88bad0..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/IMXCallListener.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2015 OpenMarket 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.matrix.android.internal.legacy.call; - -import android.view.View; - -/** - * This class tracks the call update. - */ -public interface IMXCallListener { - - /** - * Called when the call state change - * - * @param state the new call state - */ - void onStateDidChange(String state); - - /** - * Called when the call fails. - * - * @param error the failure reason - */ - void onCallError(String error); - - /** - * The call view has been created. - * It can be inserted in a custom parent view. - * - * @param callView the call view - */ - void onCallViewCreated(View callView); - - /** - * The call view has been inserted. - * The call is ready to be started. - * For an outgoing call, use placeCall(). - * For an incoming call, use launchIncomingCall(). - */ - void onReady(); - - /** - * The call was answered on another device. - */ - void onCallAnsweredElsewhere(); - - /** - * Warn that the call is ended - * - * @param aReasonId the reason of the call ending - */ - void onCallEnd(final int aReasonId); - - /** - * The video preview size has been updated. - * - * @param width the new width (non scaled size) - * @param height the new height (non scaled size) - */ - void onPreviewSizeChanged(int width, int height); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/IMXCallsManagerListener.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/IMXCallsManagerListener.java deleted file mode 100644 index 72298f3a..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/IMXCallsManagerListener.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2015 OpenMarket 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.matrix.android.internal.legacy.call; - -import im.vector.matrix.android.internal.legacy.crypto.data.MXDeviceInfo; -import im.vector.matrix.android.internal.legacy.crypto.data.MXUsersDevicesMap; - -/** - * This class manages the calls events. - */ -public interface IMXCallsManagerListener { - /** - * Called when there is an incoming call within the room. - * - * @param call the incoming call - * @param unknownDevices the unknown e2e devices list - */ - void onIncomingCall(IMXCall call, MXUsersDevicesMap unknownDevices); - - /** - * An outgoing call is started. - * - * @param call the outgoing call - */ - void onOutgoingCall(IMXCall call); - - /** - * Called when a called has been hung up - * - * @param call the incoming call - */ - void onCallHangUp(IMXCall call); - - /** - * A voip conference started in a room. - * - * @param roomId the room id - */ - void onVoipConferenceStarted(String roomId); - - /** - * A voip conference finished in a room. - * - * @param roomId the room id - */ - void onVoipConferenceFinished(String roomId); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/MXCall.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/MXCall.java deleted file mode 100644 index 4b87a3d7..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/MXCall.java +++ /dev/null @@ -1,706 +0,0 @@ -/* - * Copyright 2015 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.call; - -import android.content.Context; -import android.os.Handler; -import android.text.TextUtils; -import android.view.View; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.Timer; - -import im.vector.matrix.android.internal.legacy.MXSession; -import im.vector.matrix.android.internal.legacy.data.Room; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.util.Log; - -/** - * This class is the default implementation - */ -public class MXCall implements IMXCall { - private static final String LOG_TAG = MXCall.class.getSimpleName(); - - // defines the call timeout - public static final int CALL_TIMEOUT_MS = 120 * 1000; - - /** - * The session - */ - protected MXSession mSession; - - /** - * The context - */ - protected Context mContext; - - /** - * the turn servers - */ - protected JsonElement mTurnServer; - - /** - * The room in which the call is performed. - */ - protected Room mCallingRoom; - - /** - * The room in which the call events are sent. - * It might differ from mCallingRoom if it is a conference call. - * For a 1:1 call, it will be equal to mCallingRoom. - */ - protected Room mCallSignalingRoom; - - /** - * The call events listeners - */ - private final Set mCallListeners = new HashSet<>(); - - /** - * the call id - */ - protected String mCallId; - - /** - * Tells if it is a video call - */ - protected boolean mIsVideoCall = false; - - /** - * Tells if it is an incoming call - */ - protected boolean mIsIncoming = false; - - /** - * Tells if it is a conference call. - */ - private boolean mIsConference = false; - - /** - * List of events to sends to mCallSignalingRoom - */ - protected final List mPendingEvents = new ArrayList<>(); - - /** - * The sending eevent. - */ - private Event mPendingEvent; - - /** - * The not responding timer - */ - protected Timer mCallTimeoutTimer; - - // call start time - private long mStartTime = -1; - - // UI thread handler - final Handler mUIThreadHandler = new Handler(); - - /** - * Create the call view - */ - public void createCallView() { - } - - /** - * The activity is paused. - */ - public void onPause() { - } - - /** - * The activity is resumed. - */ - public void onResume() { - } - - // actions (must be done after dispatchOnViewReady() - - /** - * Start a call. - */ - public void placeCall(VideoLayoutConfiguration aLocalVideoPosition) { - } - - /** - * Prepare a call reception. - * - * @param aCallInviteParams the invitation Event content - * @param aCallId the call ID - * @param aLocalVideoPosition position of the local video attendee - */ - public void prepareIncomingCall(JsonObject aCallInviteParams, String aCallId, VideoLayoutConfiguration aLocalVideoPosition) { - setIsIncoming(true); - } - - /** - * The call has been detected as an incoming one. - * The application launched the dedicated activity and expects to launch the incoming call. - * - * @param aLocalVideoPosition position of the local video attendee - */ - public void launchIncomingCall(VideoLayoutConfiguration aLocalVideoPosition) { - } - - @Override - public void updateLocalVideoRendererPosition(VideoLayoutConfiguration aLocalVideoPosition) { - Log.w(LOG_TAG, "## updateLocalVideoRendererPosition(): not implemented"); - } - - @Override - public boolean switchRearFrontCamera() { - Log.w(LOG_TAG, "## switchRearFrontCamera(): not implemented"); - return false; - } - - @Override - public boolean isCameraSwitched() { - Log.w(LOG_TAG, "## isCameraSwitched(): not implemented"); - return false; - } - - @Override - public boolean isSwitchCameraSupported() { - Log.w(LOG_TAG, "## isSwitchCameraSupported(): not implemented"); - return false; - } - // events thread - - /** - * Manage the call events. - * - * @param event the call event. - */ - public void handleCallEvent(Event event) { - } - - // user actions - - /** - * The call is accepted. - */ - public void answer() { - } - - /** - * The call has been has answered on another device. - */ - public void onAnsweredElsewhere() { - - } - - /** - * The call is hung up. - */ - public void hangup(String reason) { - } - - // getters / setters - - /** - * @return the callId - */ - public String getCallId() { - return mCallId; - } - - /** - * Set the callId - */ - public void setCallId(String callId) { - mCallId = callId; - } - - /** - * @return the linked room - */ - public Room getRoom() { - return mCallingRoom; - } - - /** - * @return the call signaling room - */ - public Room getCallSignalingRoom() { - return mCallSignalingRoom; - } - - /** - * Set the linked rooms. - * - * @param room the room where the conference take place - * @param callSignalingRoom the call signaling room. - */ - public void setRooms(Room room, Room callSignalingRoom) { - mCallingRoom = room; - mCallSignalingRoom = callSignalingRoom; - } - - /** - * @return the session - */ - public MXSession getSession() { - return mSession; - } - - /** - * @return true if the call is an incoming call. - */ - public boolean isIncoming() { - return mIsIncoming; - } - - /** - * @param isIncoming true if the call is an incoming one. - */ - private void setIsIncoming(boolean isIncoming) { - mIsIncoming = isIncoming; - } - - /** - * Defines the call type - */ - public void setIsVideo(boolean isVideo) { - mIsVideoCall = isVideo; - } - - /** - * @return true if the call is a video call. - */ - public boolean isVideo() { - return mIsVideoCall; - } - - /** - * Defines the call conference status - */ - public void setIsConference(boolean isConference) { - mIsConference = isConference; - } - - /** - * @return true if the call is a conference call. - */ - public boolean isConference() { - return mIsConference; - } - - /** - * @return the callstate (must be a CALL_STATE_XX value) - */ - public String getCallState() { - return null; - } - - /** - * @return the callView - */ - public View getCallView() { - return null; - } - - /** - * @return the callView visibility - */ - public int getVisibility() { - return View.GONE; - } - - /** - * Set the callview visibility - * - * @return true if the operation succeeds - */ - public boolean setVisibility(int visibility) { - return false; - } - - /** - * @return if the call is ended. - */ - public boolean isCallEnded() { - return TextUtils.equals(CALL_STATE_ENDED, getCallState()); - } - - /** - * @return the call start time in ms since epoch, -1 if not defined. - */ - public long getCallStartTime() { - return mStartTime; - } - - /** - * @return the call elapsed time in seconds, -1 if not defined. - */ - public long getCallElapsedTime() { - if (-1 == mStartTime) { - return -1; - } - - return (System.currentTimeMillis() - mStartTime) / 1000; - } - - //============================================================================================================== - // call events listener - //============================================================================================================== - - /** - * Add a listener. - * - * @param callListener the listener to add - */ - public void addListener(IMXCallListener callListener) { - if (null != callListener) { - synchronized (LOG_TAG) { - mCallListeners.add(callListener); - } - } - } - - /** - * Remove a listener - * - * @param callListener the listener to remove - */ - public void removeListener(IMXCallListener callListener) { - if (null != callListener) { - synchronized (LOG_TAG) { - mCallListeners.remove(callListener); - } - } - } - - /** - * Remove the listeners - */ - public void clearListeners() { - synchronized (LOG_TAG) { - mCallListeners.clear(); - } - } - - /** - * @return the call listeners - */ - private Collection getCallListeners() { - Collection listeners; - - synchronized (LOG_TAG) { - listeners = new HashSet<>(mCallListeners); - } - - return listeners; - } - - /** - * Dispatch the onCallViewCreated event to the listeners. - * - * @param callView the call view - */ - protected void dispatchOnCallViewCreated(View callView) { - if (isCallEnded()) { - Log.d(LOG_TAG, "## dispatchOnCallViewCreated(): the call is ended"); - return; - } - - Log.d(LOG_TAG, "## dispatchOnCallViewCreated()"); - - Collection listeners = getCallListeners(); - - for (IMXCallListener listener : listeners) { - try { - listener.onCallViewCreated(callView); - } catch (Exception e) { - Log.e(LOG_TAG, "## dispatchOnCallViewCreated(): Exception Msg=" + e.getMessage(), e); - } - } - } - - /** - * Dispatch the onViewReady event to the listeners. - */ - protected void dispatchOnReady() { - if (isCallEnded()) { - Log.d(LOG_TAG, "## dispatchOnReady() : the call is ended"); - return; - } - - Log.d(LOG_TAG, "## dispatchOnReady()"); - - Collection listeners = getCallListeners(); - - for (IMXCallListener listener : listeners) { - try { - listener.onReady(); - } catch (Exception e) { - Log.e(LOG_TAG, "## dispatchOnReady(): Exception Msg=" + e.getMessage(), e); - } - } - } - - /** - * Dispatch the onCallError event to the listeners. - * - * @param error error message - */ - protected void dispatchOnCallError(String error) { - if (isCallEnded()) { - Log.d(LOG_TAG, "## dispatchOnCallError() : the call is ended"); - return; - } - - Log.d(LOG_TAG, "## dispatchOnCallError()"); - - Collection listeners = getCallListeners(); - - for (IMXCallListener listener : listeners) { - try { - listener.onCallError(error); - } catch (Exception e) { - Log.e(LOG_TAG, "## dispatchOnCallError(): " + e.getMessage(), e); - } - } - } - - /** - * Dispatch the onStateDidChange event to the listeners. - * - * @param newState the new state - */ - protected void dispatchOnStateDidChange(String newState) { - Log.d(LOG_TAG, "## dispatchOnCallErrorOnStateDidChange(): " + newState); - - // set the call start time - if (TextUtils.equals(CALL_STATE_CONNECTED, newState) && (-1 == mStartTime)) { - mStartTime = System.currentTimeMillis(); - } - - // the call is ended. - if (TextUtils.equals(CALL_STATE_ENDED, newState)) { - mStartTime = -1; - } - - Collection listeners = getCallListeners(); - - for (IMXCallListener listener : listeners) { - try { - listener.onStateDidChange(newState); - } catch (Exception e) { - Log.e(LOG_TAG, "## dispatchOnStateDidChange(): Exception Msg=" + e.getMessage(), e); - } - } - } - - /** - * Dispatch the onCallAnsweredElsewhere event to the listeners. - */ - protected void dispatchAnsweredElsewhere() { - Log.d(LOG_TAG, "## dispatchAnsweredElsewhere()"); - - Collection listeners = getCallListeners(); - - for (IMXCallListener listener : listeners) { - try { - listener.onCallAnsweredElsewhere(); - } catch (Exception e) { - Log.e(LOG_TAG, "## dispatchAnsweredElsewhere(): Exception Msg=" + e.getMessage(), e); - } - } - } - - /** - * Dispatch the onCallEnd event to the listeners. - * - * @param aEndCallReasonId the reason of the call ending - */ - protected void dispatchOnCallEnd(int aEndCallReasonId) { - Log.d(LOG_TAG, "## dispatchOnCallEnd(): endReason=" + aEndCallReasonId); - - Collection listeners = getCallListeners(); - - for (IMXCallListener listener : listeners) { - try { - listener.onCallEnd(aEndCallReasonId); - } catch (Exception e) { - Log.e(LOG_TAG, "## dispatchOnCallEnd(): Exception Msg=" + e.getMessage(), e); - } - } - } - - /** - * Send the next pending events - */ - protected void sendNextEvent() { - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - // do not send any new message - if (isCallEnded() && (null != mPendingEvents)) { - mPendingEvents.clear(); - } - - // ready to send - if ((null == mPendingEvent) && (0 != mPendingEvents.size())) { - mPendingEvent = mPendingEvents.get(0); - mPendingEvents.remove(mPendingEvent); - - Log.d(LOG_TAG, "## sendNextEvent() : sending event of type " + mPendingEvent.getType() + " event id " + mPendingEvent.eventId); - mCallSignalingRoom.sendEvent(mPendingEvent, new ApiCallback() { - @Override - public void onSuccess(Void info) { - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - Log.d(LOG_TAG, "## sendNextEvent() : event " + mPendingEvent.eventId + " is sent"); - - mPendingEvent = null; - sendNextEvent(); - } - }); - } - - private void commonFailure(String reason) { - Log.d(LOG_TAG, "## sendNextEvent() : event " + mPendingEvent.eventId + " failed to be sent " + reason); - - // let try next candidate event - if (TextUtils.equals(mPendingEvent.getType(), Event.EVENT_TYPE_CALL_CANDIDATES)) { - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - mPendingEvent = null; - sendNextEvent(); - } - }); - } else { - hangup(reason); - } - } - - @Override - public void onNetworkError(Exception e) { - commonFailure(e.getLocalizedMessage()); - } - - @Override - public void onMatrixError(MatrixError e) { - commonFailure(e.getLocalizedMessage()); - } - - @Override - public void onUnexpectedError(Exception e) { - commonFailure(e.getLocalizedMessage()); - } - }); - } - } - }); - } - - /** - * Dispatch the onPreviewSizeChanged event to the listeners. - * - * @param width the preview width - * @param height the preview height - */ - protected void dispatchOnPreviewSizeChanged(int width, int height) { - Log.d(LOG_TAG, "## dispatchOnPreviewSizeChanged(): width =" + width + " - height =" + height); - - Collection listeners = getCallListeners(); - - for (IMXCallListener listener : listeners) { - try { - listener.onPreviewSizeChanged(width, height); - } catch (Exception e) { - Log.e(LOG_TAG, "## dispatchOnPreviewSizeChanged(): Exception Msg=" + e.getMessage(), e); - } - } - } - - /** - * send an hang up event - * - * @param reason the reason - */ - protected void sendHangup(String reason) { - JsonObject hangupContent = new JsonObject(); - - hangupContent.add("version", new JsonPrimitive(0)); - hangupContent.add("call_id", new JsonPrimitive(mCallId)); - - if (!TextUtils.isEmpty(reason)) { - hangupContent.add("reason", new JsonPrimitive(reason)); - } - - Event event = new Event(Event.EVENT_TYPE_CALL_HANGUP, hangupContent, mSession.getCredentials().getUserId(), mCallSignalingRoom.getRoomId()); - - // local notification to indicate the end of call - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - dispatchOnCallEnd(END_CALL_REASON_USER_HIMSELF); - } - }); - - Log.d(LOG_TAG, "## sendHangup(): reason=" + reason); - - // send hang up event to the server - mCallSignalingRoom.sendEvent(event, new ApiCallback() { - @Override - public void onSuccess(Void info) { - Log.d(LOG_TAG, "## sendHangup(): onSuccess"); - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "## sendHangup(): onNetworkError Msg=" + e.getMessage(), e); - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "## sendHangup(): onMatrixError Msg=" + e.getMessage()); - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "## sendHangup(): onUnexpectedError Msg=" + e.getMessage(), e); - } - }); - } - - @Override - public void muteVideoRecording(boolean isVideoMuted) { - Log.w(LOG_TAG, "## muteVideoRecording(): not implemented"); - } - - @Override - public boolean isVideoRecordingMuted() { - Log.w(LOG_TAG, "## muteVideoRecording(): not implemented - default value = false"); - return false; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/MXCallListener.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/MXCallListener.java deleted file mode 100644 index 53dd5f37..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/MXCallListener.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2015 OpenMarket 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.matrix.android.internal.legacy.call; - -import android.view.View; - -/** - * This class is the default implementation of IMXCallListener. - */ -public class MXCallListener implements IMXCallListener { - - @Override - public void onStateDidChange(String state) { - } - - @Override - public void onCallError(String error) { - } - - @Override - public void onCallViewCreated(View callView) { - } - - @Override - public void onReady() { - } - - @Override - public void onCallAnsweredElsewhere() { - } - - @Override - public void onCallEnd(final int aReasonId) { - } - - @Override - public void onPreviewSizeChanged(int width, int height) { - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/MXCallsManager.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/MXCallsManager.java deleted file mode 100644 index 1d99f693..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/MXCallsManager.java +++ /dev/null @@ -1,1295 +0,0 @@ -/* - * Copyright 2015 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.call; - -import android.content.Context; -import android.os.Handler; -import android.os.Looper; -import android.text.TextUtils; -import android.util.Base64; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; - -import im.vector.matrix.android.internal.legacy.MXPatterns; -import im.vector.matrix.android.internal.legacy.MXSession; -import im.vector.matrix.android.internal.legacy.crypto.MXCryptoError; -import im.vector.matrix.android.internal.legacy.crypto.data.MXDeviceInfo; -import im.vector.matrix.android.internal.legacy.crypto.data.MXUsersDevicesMap; -import im.vector.matrix.android.internal.legacy.data.Room; -import im.vector.matrix.android.internal.legacy.data.RoomState; -import im.vector.matrix.android.internal.legacy.data.store.IMXStore; -import im.vector.matrix.android.internal.legacy.listeners.MXEventListener; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.SimpleApiCallback; -import im.vector.matrix.android.internal.legacy.rest.client.CallRestClient; -import im.vector.matrix.android.internal.legacy.rest.model.CreateRoomParams; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.EventContent; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.rest.model.RoomMember; -import im.vector.matrix.android.internal.legacy.util.JsonUtils; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.Timer; -import java.util.TimerTask; - -public class MXCallsManager { - private static final String LOG_TAG = MXCallsManager.class.getSimpleName(); - - /** - * Defines the call classes. - */ - public enum CallClass { - // disabled because of https://github.com/vector-im/riot-android/issues/1660 - //CHROME_CLASS, - WEBRTC_CLASS, - DEFAULT_CLASS - } - - private MXSession mSession = null; - private Context mContext = null; - - private CallRestClient mCallResClient = null; - private JsonElement mTurnServer = null; - private Timer mTurnServerTimer = null; - private boolean mSuspendTurnServerRefresh = false; - - private CallClass mPreferredCallClass = CallClass.WEBRTC_CLASS; - - // active calls - private final Map mCallsByCallId = new HashMap<>(); - - // listeners - private final Set mListeners = new HashSet<>(); - - // incoming calls - private final Set mxPendingIncomingCallId = new HashSet<>(); - - // UI handler - private final Handler mUIThreadHandler; - - /** - * To create an outgoing call - * 1- CallsManager.createCallInRoom() - * 2- on success, IMXCall.createCallView - * 3- IMXCallListener.onCallViewCreated(callview) -> insert the callview - * 4- IMXCallListener.onCallReady() -> IMXCall.placeCall() - * 5- the call states should follow theses steps - * CALL_STATE_WAIT_LOCAL_MEDIA - * CALL_STATE_WAIT_CREATE_OFFER - * CALL_STATE_INVITE_SENT - * CALL_STATE_RINGING - * 6- the callee accepts the call - * CALL_STATE_CONNECTING - * CALL_STATE_CONNECTED - * - * To manage an incoming call - * 1- IMXCall.createCallView - * 2- IMXCallListener.onCallViewCreated(callview) -> insert the callview - * 3- IMXCallListener.onCallReady(), IMXCall.launchIncomingCall() - * 4- the call states should follow theses steps - * CALL_STATE_WAIT_LOCAL_MEDIA - * CALL_STATE_RINGING - * 5- The user accepts the call, IMXCall.answer() - * 6- the states should be - * CALL_STATE_CREATE_ANSWER - * CALL_STATE_CONNECTING - * CALL_STATE_CONNECTED - */ - - /** - * Constructor - * - * @param session the session - * @param context the context - */ - public MXCallsManager(MXSession session, Context context) { - mSession = session; - mContext = context; - - mUIThreadHandler = new Handler(Looper.getMainLooper()); - - mCallResClient = mSession.getCallRestClient(); - - mSession.getDataHandler().addListener(new MXEventListener() { - @Override - public void onLiveEvent(Event event, RoomState roomState) { - if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_STATE_ROOM_MEMBER)) { - // Listen to the membership join/leave events to detect the conference user activity. - // This mechanism detects the presence of an established conf call - if (TextUtils.equals(event.sender, MXCallsManager.getConferenceUserId(event.roomId))) { - EventContent eventContent = JsonUtils.toEventContent(event.getContentAsJsonObject()); - - if (TextUtils.equals(eventContent.membership, RoomMember.MEMBERSHIP_LEAVE)) { - dispatchOnVoipConferenceFinished(event.roomId); - } - if (TextUtils.equals(eventContent.membership, RoomMember.MEMBERSHIP_JOIN)) { - dispatchOnVoipConferenceStarted(event.roomId); - } - } - } - } - }); - - refreshTurnServer(); - } - - /** - * @return true if the call feature is supported - */ - public boolean isSupported() { - return /*MXChromeCall.isSupported() || */ MXWebRtcCall.isSupported(mContext); - } - - /** - * @return the list of supported classes - */ - public Collection supportedClass() { - List list = new ArrayList<>(); - - /*if (MXChromeCall.isSupported()) { - list.add(CallClass.CHROME_CLASS); - }*/ - - if (MXWebRtcCall.isSupported(mContext)) { - list.add(CallClass.WEBRTC_CLASS); - } - - Log.d(LOG_TAG, "supportedClass " + list); - - return list; - } - - /** - * @param callClass set the default callClass - */ - public void setDefaultCallClass(CallClass callClass) { - Log.d(LOG_TAG, "setDefaultCallClass " + callClass); - - boolean isUpdatable = false; - - /*if (callClass == CallClass.CHROME_CLASS) { - isUpdatable = MXChromeCall.isSupported(); - }*/ - - if (callClass == CallClass.WEBRTC_CLASS) { - isUpdatable = MXWebRtcCall.isSupported(mContext); - } - - if (isUpdatable) { - mPreferredCallClass = callClass; - } - } - - /** - * create a new call - * - * @param callId the call Id (null to use a default value) - * @return the IMXCall - */ - private IMXCall createCall(String callId) { - Log.d(LOG_TAG, "createCall " + callId); - - IMXCall call = null; - - // default - /*if (((CallClass.CHROME_CLASS == mPreferredCallClass) || (CallClass.DEFAULT_CLASS == mPreferredCallClass)) && MXChromeCall.isSupported()) { - call = new MXChromeCall(mSession, mContext, getTurnServer()); - }*/ - - // webrtc - if (null == call) { - try { - call = new MXWebRtcCall(mSession, mContext, getTurnServer()); - } catch (Exception e) { - Log.e(LOG_TAG, "createCall " + e.getMessage(), e); - } - } - - // a valid callid is provided - if (null != callId) { - call.setCallId(callId); - } - - return call; - } - - /** - * Search a call from its dedicated room id. - * - * @param roomId the room id - * @return the IMXCall if it exists - */ - public IMXCall getCallWithRoomId(String roomId) { - List calls; - - synchronized (this) { - calls = new ArrayList<>(mCallsByCallId.values()); - } - - for (IMXCall call : calls) { - if (TextUtils.equals(roomId, call.getRoom().getRoomId())) { - if (TextUtils.equals(call.getCallState(), IMXCall.CALL_STATE_ENDED)) { - Log.d(LOG_TAG, "## getCallWithRoomId() : the call " + call.getCallId() + " has been stopped"); - synchronized (this) { - mCallsByCallId.remove(call.getCallId()); - } - } else { - return call; - } - } - } - - return null; - } - - /** - * Returns the IMXCall from its callId. - * - * @param callId the call Id - * @return the IMXCall if it exists - */ - public IMXCall getCallWithCallId(String callId) { - return getCallWithCallId(callId, false); - } - - /** - * Returns the IMXCall from its callId. - * - * @param callId the call Id - * @param create create the IMXCall if it does not exist - * @return the IMXCall if it exists - */ - private IMXCall getCallWithCallId(String callId, boolean create) { - IMXCall call = null; - - // check if the call exists - if (null != callId) { - synchronized (this) { - call = mCallsByCallId.get(callId); - } - } - - // test if the call has been stopped - if ((null != call) && TextUtils.equals(call.getCallState(), IMXCall.CALL_STATE_ENDED)) { - Log.d(LOG_TAG, "## getCallWithCallId() : the call " + callId + " has been stopped"); - synchronized (this) { - mCallsByCallId.remove(call.getCallId()); - } - - call = null; - } - - // the call does not exist but request to create it - if ((null == call) && create) { - call = createCall(callId); - synchronized (this) { - mCallsByCallId.put(call.getCallId(), call); - } - } - - Log.d(LOG_TAG, "getCallWithCallId " + callId + " " + call); - - return call; - } - - /** - * Tell if a call is in progress. - * - * @param call the call - * @return true if the call is in progress - */ - public static boolean isCallInProgress(IMXCall call) { - boolean res = false; - - if (null != call) { - String callState = call.getCallState(); - res = TextUtils.equals(callState, IMXCall.CALL_STATE_CREATED) - || TextUtils.equals(callState, IMXCall.CALL_STATE_CREATING_CALL_VIEW) - || TextUtils.equals(callState, IMXCall.CALL_STATE_READY) - || TextUtils.equals(callState, IMXCall.CALL_STATE_WAIT_LOCAL_MEDIA) - || TextUtils.equals(callState, IMXCall.CALL_STATE_WAIT_CREATE_OFFER) - || TextUtils.equals(callState, IMXCall.CALL_STATE_INVITE_SENT) - || TextUtils.equals(callState, IMXCall.CALL_STATE_RINGING) - || TextUtils.equals(callState, IMXCall.CALL_STATE_CREATE_ANSWER) - || TextUtils.equals(callState, IMXCall.CALL_STATE_CONNECTING) - || TextUtils.equals(callState, IMXCall.CALL_STATE_CONNECTED); - } - - return res; - } - - /** - * @return true if there are some active calls. - */ - public boolean hasActiveCalls() { - synchronized (this) { - List callIdsToRemove = new ArrayList<>(); - - Set callIds = mCallsByCallId.keySet(); - - for (String callId : callIds) { - IMXCall call = mCallsByCallId.get(callId); - - if (TextUtils.equals(call.getCallState(), IMXCall.CALL_STATE_ENDED)) { - Log.d(LOG_TAG, "# hasActiveCalls() : the call " + callId + " is not anymore valid"); - callIdsToRemove.add(callId); - } else { - Log.d(LOG_TAG, "# hasActiveCalls() : the call " + callId + " is active"); - return true; - } - } - - for (String callIdToRemove : callIdsToRemove) { - mCallsByCallId.remove(callIdToRemove); - } - } - - Log.d(LOG_TAG, "# hasActiveCalls() : no active call"); - return false; - } - - /** - * Manage the call events. - * - * @param store the dedicated store - * @param event the call event. - */ - public void handleCallEvent(final IMXStore store, final Event event) { - if (event.isCallEvent() && isSupported()) { - Log.d(LOG_TAG, "handleCallEvent " + event.getType()); - - // always run the call event in the UI thread - // MXChromeCall does not work properly in other thread (because of the webview) - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - boolean isMyEvent = TextUtils.equals(event.getSender(), mSession.getMyUserId()); - Room room = mSession.getDataHandler().getRoom(store, event.roomId, true); - - String callId = null; - JsonObject eventContent = null; - - try { - eventContent = event.getContentAsJsonObject(); - callId = eventContent.getAsJsonPrimitive("call_id").getAsString(); - } catch (Exception e) { - Log.e(LOG_TAG, "handleCallEvent : fail to retrieve call_id " + e.getMessage(), e); - } - // sanity check - if ((null != callId) && (null != room)) { - // receive an invitation - if (Event.EVENT_TYPE_CALL_INVITE.equals(event.getType())) { - long lifeTime = event.getAge(); - - if (Long.MAX_VALUE == lifeTime) { - lifeTime = System.currentTimeMillis() - event.getOriginServerTs(); - } - - // ignore older call messages - if (lifeTime < MXCall.CALL_TIMEOUT_MS) { - // create the call only it is triggered from someone else - IMXCall call = getCallWithCallId(callId, !isMyEvent); - - // sanity check - if (null != call) { - // init the information - if (null == call.getRoom()) { - call.setRooms(room, room); - } - - if (!isMyEvent) { - call.prepareIncomingCall(eventContent, callId, null); - mxPendingIncomingCallId.add(callId); - } else { - call.handleCallEvent(event); - } - } - } else { - Log.d(LOG_TAG, "## handleCallEvent() : " + Event.EVENT_TYPE_CALL_INVITE + " is ignored because it is too old"); - } - } else if (Event.EVENT_TYPE_CALL_CANDIDATES.equals(event.getType())) { - if (!isMyEvent) { - IMXCall call = getCallWithCallId(callId); - - if (null != call) { - if (null == call.getRoom()) { - call.setRooms(room, room); - } - call.handleCallEvent(event); - } - } - } else if (Event.EVENT_TYPE_CALL_ANSWER.equals(event.getType())) { - IMXCall call = getCallWithCallId(callId); - - if (null != call) { - // assume it is a catch up call. - // the creation / candidates / - // the call has been answered on another device - if (IMXCall.CALL_STATE_CREATED.equals(call.getCallState())) { - call.onAnsweredElsewhere(); - synchronized (this) { - mCallsByCallId.remove(callId); - } - } else { - if (null == call.getRoom()) { - call.setRooms(room, room); - } - call.handleCallEvent(event); - } - } - } else if (Event.EVENT_TYPE_CALL_HANGUP.equals(event.getType())) { - final IMXCall call = getCallWithCallId(callId); - if (null != call) { - // trigger call events only if the call is active - final boolean isActiveCall = !IMXCall.CALL_STATE_CREATED.equals(call.getCallState()); - - if (null == call.getRoom()) { - call.setRooms(room, room); - } - - if (isActiveCall) { - call.handleCallEvent(event); - } - - synchronized (this) { - mCallsByCallId.remove(callId); - } - - // warn that a call has been hung up - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - // must warn anyway any listener that the call has been killed - // for example, when the device is in locked screen - // the callview is not created but the device is ringing - // if the other participant ends the call, the ring should stop - dispatchOnCallHangUp(call); - } - }); - } - } - } - } - }); - } - } - - /** - * check if there is a pending incoming call - */ - public void checkPendingIncomingCalls() { - //Log.d(LOG_TAG, "checkPendingIncomingCalls"); - - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - if (mxPendingIncomingCallId.size() > 0) { - for (String callId : mxPendingIncomingCallId) { - final IMXCall call = getCallWithCallId(callId); - - if (null != call) { - final Room room = call.getRoom(); - - // for encrypted rooms with 2 members - // check if there are some unknown devices before warning - // of the incoming call. - // If there are some unknown devices, the answer event would not be encrypted. - if ((null != room) - && room.isEncrypted() - && mSession.getCrypto().warnOnUnknownDevices() - && room.getNumberOfJoinedMembers() == 2) { - - // test if the encrypted events are sent only to the verified devices (any room) - mSession.getCrypto().getGlobalBlacklistUnverifiedDevices(new SimpleApiCallback() { - @Override - public void onSuccess(Boolean sendToVerifiedDevicesOnly) { - if (sendToVerifiedDevicesOnly) { - dispatchOnIncomingCall(call, null); - } else { - // test if the encrypted events are sent only to the verified devices (only this room) - mSession.getCrypto().isRoomBlacklistUnverifiedDevices(room.getRoomId(), new SimpleApiCallback() { - @Override - public void onSuccess(Boolean sendToVerifiedDevicesOnly) { - if (sendToVerifiedDevicesOnly) { - dispatchOnIncomingCall(call, null); - } else { - room.getJoinedMembersAsync(new ApiCallback>() { - - @Override - public void onNetworkError(Exception e) { - dispatchOnIncomingCall(call, null); - } - - @Override - public void onMatrixError(MatrixError e) { - dispatchOnIncomingCall(call, null); - } - - @Override - public void onUnexpectedError(Exception e) { - dispatchOnIncomingCall(call, null); - } - - @Override - public void onSuccess(List members) { - String userId1 = members.get(0).getUserId(); - String userId2 = members.get(1).getUserId(); - - Log.d(LOG_TAG, "## checkPendingIncomingCalls() : check the unknown devices"); - - // - mSession.getCrypto() - .checkUnknownDevices(Arrays.asList(userId1, userId2), new ApiCallback() { - @Override - public void onSuccess(Void anything) { - Log.d(LOG_TAG, "## checkPendingIncomingCalls() : no unknown device"); - dispatchOnIncomingCall(call, null); - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, - "## checkPendingIncomingCalls() : checkUnknownDevices failed " - + e.getMessage(), e); - dispatchOnIncomingCall(call, null); - } - - @Override - public void onMatrixError(MatrixError e) { - MXUsersDevicesMap unknownDevices = null; - - if (e instanceof MXCryptoError) { - MXCryptoError cryptoError = (MXCryptoError) e; - - if (MXCryptoError.UNKNOWN_DEVICES_CODE.equals(cryptoError.errcode)) { - unknownDevices = - (MXUsersDevicesMap) cryptoError.mExceptionData; - } - } - - if (null != unknownDevices) { - Log.d(LOG_TAG, "## checkPendingIncomingCalls() :" + - " checkUnknownDevices found some unknown devices"); - } else { - Log.e(LOG_TAG, "## checkPendingIncomingCalls() :" + - " checkUnknownDevices failed " + e.getMessage()); - } - - dispatchOnIncomingCall(call, unknownDevices); - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "## checkPendingIncomingCalls() :" + - " checkUnknownDevices failed " + e.getMessage(), e); - dispatchOnIncomingCall(call, null); - } - }); - } - }); - } - } - }); - } - } - }); - } else { - dispatchOnIncomingCall(call, null); - } - } - } - } - mxPendingIncomingCallId.clear(); - } - }); - } - - /** - * Create an IMXCall in the room defines by its room Id. - * -> for a 1:1 call, it is a standard call. - * -> for a conference call, - * ----> the conference user is invited to the room (if it was not yet invited) - * ----> the call signaling room is created (or retrieved) with the conference - * ----> and the call is started - * - * @param roomId the room roomId - * @param isVideo true to start a video call - * @param callback the async callback - */ - public void createCallInRoom(final String roomId, final boolean isVideo, final ApiCallback callback) { - Log.d(LOG_TAG, "createCallInRoom in " + roomId); - - final Room room = mSession.getDataHandler().getRoom(roomId); - - // sanity check - if (null != room) { - if (isSupported()) { - int joinedMembers = room.getNumberOfJoinedMembers(); - - Log.d(LOG_TAG, "createCallInRoom : the room has " + joinedMembers + " joined members"); - - if (joinedMembers > 1) { - if (joinedMembers == 2) { - // when a room is encrypted, test first there is no unknown device - // else the call will fail. - // So it seems safer to reject the call creation it it will fail. - if (room.isEncrypted() && mSession.getCrypto().warnOnUnknownDevices()) { - room.getJoinedMembersAsync(new SimpleApiCallback>(callback) { - @Override - public void onSuccess(List members) { - if (members.size() != 2) { - // Safety check - callback.onUnexpectedError(new Exception("Wrong number of members")); - return; - } - - String userId1 = members.get(0).getUserId(); - String userId2 = members.get(1).getUserId(); - - // force the refresh to ensure that the devices list is up-to-date - mSession.getCrypto().checkUnknownDevices(Arrays.asList(userId1, userId2), new SimpleApiCallback(callback) { - @Override - public void onSuccess(Void anything) { - final IMXCall call = getCallWithCallId(null, true); - call.setRooms(room, room); - call.setIsVideo(isVideo); - dispatchOnOutgoingCall(call); - - if (null != callback) { - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - callback.onSuccess(call); - } - }); - } - } - }); - } - }); - } else { - final IMXCall call = getCallWithCallId(null, true); - call.setIsVideo(isVideo); - dispatchOnOutgoingCall(call); - call.setRooms(room, room); - - if (null != callback) { - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - callback.onSuccess(call); - } - }); - } - } - } else { - Log.d(LOG_TAG, "createCallInRoom : inviteConferenceUser"); - - inviteConferenceUser(room, new ApiCallback() { - @Override - public void onSuccess(Void info) { - Log.d(LOG_TAG, "createCallInRoom : inviteConferenceUser succeeds"); - - getConferenceUserRoom(room.getRoomId(), new ApiCallback() { - @Override - public void onSuccess(Room conferenceRoom) { - - Log.d(LOG_TAG, "createCallInRoom : getConferenceUserRoom succeeds"); - - final IMXCall call = getCallWithCallId(null, true); - call.setRooms(room, conferenceRoom); - call.setIsConference(true); - call.setIsVideo(isVideo); - dispatchOnOutgoingCall(call); - - if (null != callback) { - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - callback.onSuccess(call); - } - }); - } - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "createCallInRoom : getConferenceUserRoom failed " + e.getMessage(), e); - - if (null != callback) { - callback.onNetworkError(e); - } - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "createCallInRoom : getConferenceUserRoom failed " + e.getMessage()); - - - if (null != callback) { - callback.onMatrixError(e); - } - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "createCallInRoom : getConferenceUserRoom failed " + e.getMessage(), e); - - if (null != callback) { - callback.onUnexpectedError(e); - } - } - }); - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "createCallInRoom : inviteConferenceUser fails " + e.getMessage(), e); - - if (null != callback) { - callback.onNetworkError(e); - } - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "createCallInRoom : inviteConferenceUser fails " + e.getMessage()); - - if (null != callback) { - callback.onMatrixError(e); - } - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "createCallInRoom : inviteConferenceUser fails " + e.getMessage(), e); - - if (null != callback) { - callback.onUnexpectedError(e); - } - } - }); - } - } else { - if (null != callback) { - callback.onMatrixError(new MatrixError(MatrixError.NOT_SUPPORTED, "too few users")); - } - } - } else { - if (null != callback) { - callback.onMatrixError(new MatrixError(MatrixError.NOT_SUPPORTED, "VOIP is not supported")); - } - } - } else { - if (null != callback) { - callback.onMatrixError(new MatrixError(MatrixError.NOT_FOUND, "room not found")); - } - } - } - - //============================================================================================================== - // Turn servers management - //============================================================================================================== - - /** - * Suspend the turn server refresh - */ - public void pauseTurnServerRefresh() { - mSuspendTurnServerRefresh = true; - } - - /** - * Refresh the turn servers until it succeeds. - */ - public void unpauseTurnServerRefresh() { - Log.d(LOG_TAG, "unpauseTurnServerRefresh"); - - mSuspendTurnServerRefresh = false; - if (null != mTurnServerTimer) { - mTurnServerTimer.cancel(); - mTurnServerTimer = null; - } - refreshTurnServer(); - } - - /** - * Stop the turn servers refresh. - */ - public void stopTurnServerRefresh() { - Log.d(LOG_TAG, "stopTurnServerRefresh"); - - mSuspendTurnServerRefresh = true; - if (null != mTurnServerTimer) { - mTurnServerTimer.cancel(); - mTurnServerTimer = null; - } - } - - /** - * @return the turn server - */ - private JsonElement getTurnServer() { - JsonElement res; - - synchronized (LOG_TAG) { - res = mTurnServer; - } - - // privacy logs - //Log.d(LOG_TAG, "getTurnServer " + res); - Log.d(LOG_TAG, "getTurnServer "); - - return res; - } - - /** - * Refresh the turn servers. - */ - private void refreshTurnServer() { - if (mSuspendTurnServerRefresh) { - return; - } - - Log.d(LOG_TAG, "## refreshTurnServer () starts"); - - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - mCallResClient.getTurnServer(new ApiCallback() { - private void restartAfter(int msDelay) { - // reported by GA - // "ttl" seems invalid - if (msDelay <= 0) { - Log.e(LOG_TAG, "## refreshTurnServer() : invalid delay " + msDelay); - } else { - if (null != mTurnServerTimer) { - mTurnServerTimer.cancel(); - } - - try { - mTurnServerTimer = new Timer(); - mTurnServerTimer.schedule(new TimerTask() { - @Override - public void run() { - if (mTurnServerTimer != null) { - mTurnServerTimer.cancel(); - mTurnServerTimer = null; - } - - refreshTurnServer(); - } - }, msDelay); - } catch (Throwable e) { - Log.e(LOG_TAG, "## refreshTurnServer() failed to start the timer", e); - - if (null != mTurnServerTimer) { - mTurnServerTimer.cancel(); - mTurnServerTimer = null; - } - refreshTurnServer(); - } - } - } - - @Override - public void onSuccess(JsonObject info) { - // privacy - Log.d(LOG_TAG, "## refreshTurnServer () : onSuccess"); - //Log.d(LOG_TAG, "onSuccess " + info); - - if (null != info) { - if (info.has("uris")) { - synchronized (LOG_TAG) { - mTurnServer = info; - } - } - - if (info.has("ttl")) { - int ttl = 60000; - - try { - ttl = info.get("ttl").getAsInt(); - // restart a 90 % before ttl expires - ttl = ttl * 9 / 10; - } catch (Exception e) { - Log.e(LOG_TAG, "Fail to retrieve ttl " + e.getMessage(), e); - } - - Log.d(LOG_TAG, "## refreshTurnServer () : onSuccess : retry after " + ttl + " seconds"); - restartAfter(ttl * 1000); - } - } - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "## refreshTurnServer () : onNetworkError", e); - restartAfter(60000); - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "## refreshTurnServer () : onMatrixError() : " + e.errcode); - - if (TextUtils.equals(e.errcode, MatrixError.LIMIT_EXCEEDED) && (null != e.retry_after_ms)) { - Log.e(LOG_TAG, "## refreshTurnServer () : onMatrixError() : retry after " + e.retry_after_ms + " ms"); - restartAfter(e.retry_after_ms); - } - } - - @Override - public void onUnexpectedError(Exception e) { - // should never happen - Log.e(LOG_TAG, "## refreshTurnServer () : onUnexpectedError()", e); - } - }); - } - }); - } - - //============================================================================================================== - // Conference call - //============================================================================================================== - - - // Copied from vector-web: - // FIXME: This currently forces Vector to try to hit the matrix.org AS for conferencing. - // This is bad because it prevents people running their own ASes from being used. - // This isn't permanent and will be customisable in the future: see the proposal - // at docs/conferencing.md for more info. - private static final String USER_PREFIX = "fs_"; - private static final String DOMAIN = "matrix.org"; - private static final Map mConferenceUserIdByRoomId = new HashMap<>(); - - /** - * Return the id of the conference user dedicated for a room Id - * - * @param roomId the room id - * @return the conference user id - */ - public static String getConferenceUserId(String roomId) { - // sanity check - if (null == roomId) { - return null; - } - - String conferenceUserId = mConferenceUserIdByRoomId.get(roomId); - - // it does not exist, compute it. - if (null == conferenceUserId) { - byte[] data = null; - - try { - data = roomId.getBytes("UTF-8"); - } catch (Exception e) { - Log.e(LOG_TAG, "conferenceUserIdForRoom failed " + e.getMessage(), e); - } - - if (null == data) { - return null; - } - - String base64 = Base64.encodeToString(data, Base64.NO_WRAP | Base64.URL_SAFE).replace("=", ""); - conferenceUserId = "@" + USER_PREFIX + base64 + ":" + DOMAIN; - - mConferenceUserIdByRoomId.put(roomId, conferenceUserId); - } - - return conferenceUserId; - } - - /** - * Test if the provided user is a valid conference user Id - * - * @param userId the user id to test - * @return true if it is a valid conference user id - */ - public static boolean isConferenceUserId(String userId) { - // test first if it a known conference user id - if (mConferenceUserIdByRoomId.values().contains(userId)) { - return true; - } - - boolean res = false; - - String prefix = "@" + USER_PREFIX; - String suffix = ":" + DOMAIN; - - if (!TextUtils.isEmpty(userId) && userId.startsWith(prefix) && userId.endsWith(suffix)) { - String roomIdBase64 = userId.substring(prefix.length(), userId.length() - suffix.length()); - try { - res = MXPatterns.isRoomId((new String(Base64.decode(roomIdBase64, Base64.NO_WRAP | Base64.URL_SAFE), "UTF-8"))); - } catch (Exception e) { - Log.e(LOG_TAG, "isConferenceUserId : failed " + e.getMessage(), e); - } - } - - return res; - } - - /** - * Invite the conference user to a room. - * It is mandatory before starting a conference call. - * - * @param room the room - * @param callback the async callback - */ - private void inviteConferenceUser(final Room room, final ApiCallback callback) { - Log.d(LOG_TAG, "inviteConferenceUser " + room.getRoomId()); - - String conferenceUserId = getConferenceUserId(room.getRoomId()); - RoomMember conferenceMember = room.getMember(conferenceUserId); - - if ((null != conferenceMember) && TextUtils.equals(conferenceMember.membership, RoomMember.MEMBERSHIP_JOIN)) { - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - callback.onSuccess(null); - } - }); - } else { - room.invite(conferenceUserId, callback); - } - } - - /** - * Get the room with the conference user dedicated for the passed room. - * - * @param roomId the room id. - * @param callback the async callback. - */ - private void getConferenceUserRoom(final String roomId, final ApiCallback callback) { - Log.d(LOG_TAG, "getConferenceUserRoom with room id " + roomId); - - String conferenceUserId = getConferenceUserId(roomId); - - Room conferenceRoom = null; - Collection rooms = mSession.getDataHandler().getStore().getRooms(); - - // Use an existing 1:1 with the conference user; else make one - for (Room room : rooms) { - if (room.isConferenceUserRoom() && room.getNumberOfMembers() == 2 && null != room.getMember(conferenceUserId)) { - conferenceRoom = room; - break; - } - } - - if (null != conferenceRoom) { - Log.d(LOG_TAG, "getConferenceUserRoom : the room already exists"); - - final Room fConferenceRoom = conferenceRoom; - mSession.getDataHandler().getStore().commit(); - - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - callback.onSuccess(fConferenceRoom); - } - }); - } else { - Log.d(LOG_TAG, "getConferenceUserRoom : create the room"); - - CreateRoomParams params = new CreateRoomParams(); - params.preset = CreateRoomParams.PRESET_PRIVATE_CHAT; - params.invitedUserIds = Arrays.asList(conferenceUserId); - - mSession.createRoom(params, new ApiCallback() { - @Override - public void onSuccess(String roomId) { - Log.d(LOG_TAG, "getConferenceUserRoom : the room creation succeeds"); - - Room room = mSession.getDataHandler().getRoom(roomId); - - if (null != room) { - room.setIsConferenceUserRoom(true); - mSession.getDataHandler().getStore().commit(); - callback.onSuccess(room); - } - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "getConferenceUserRoom : failed " + e.getMessage(), e); - callback.onNetworkError(e); - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "getConferenceUserRoom : failed " + e.getMessage()); - callback.onMatrixError(e); - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "getConferenceUserRoom : failed " + e.getMessage(), e); - callback.onUnexpectedError(e); - } - }); - } - } - - //============================================================================================================== - // listeners management - //============================================================================================================== - - /** - * Add a listener - * - * @param listener the listener to add - */ - public void addListener(IMXCallsManagerListener listener) { - if (null != listener) { - synchronized (this) { - mListeners.add(listener); - } - } - } - - /** - * Remove a listener - * - * @param listener the listener to remove - */ - public void removeListener(IMXCallsManagerListener listener) { - if (null != listener) { - synchronized (this) { - mListeners.remove(listener); - } - } - } - - /** - * @return a copy of the listeners - */ - private Collection getListeners() { - Collection listeners; - - synchronized (this) { - listeners = new HashSet<>(mListeners); - } - - return listeners; - } - - /** - * dispatch the onIncomingCall event to the listeners - * - * @param call the call - * @param unknownDevices the unknown e2e devices list. - */ - private void dispatchOnIncomingCall(IMXCall call, final MXUsersDevicesMap unknownDevices) { - Log.d(LOG_TAG, "dispatchOnIncomingCall " + call.getCallId()); - - Collection listeners = getListeners(); - - for (IMXCallsManagerListener l : listeners) { - try { - l.onIncomingCall(call, unknownDevices); - } catch (Exception e) { - Log.e(LOG_TAG, "dispatchOnIncomingCall " + e.getMessage(), e); - } - } - } - - /** - * dispatch the call creation to the listeners - * - * @param call the call - */ - private void dispatchOnOutgoingCall(IMXCall call) { - Log.d(LOG_TAG, "dispatchOnOutgoingCall " + call.getCallId()); - - Collection listeners = getListeners(); - - for (IMXCallsManagerListener l : listeners) { - try { - l.onOutgoingCall(call); - } catch (Exception e) { - Log.e(LOG_TAG, "dispatchOnOutgoingCall " + e.getMessage(), e); - } - } - } - - /** - * dispatch the onCallHangUp event to the listeners - * - * @param call the call - */ - private void dispatchOnCallHangUp(IMXCall call) { - Log.d(LOG_TAG, "dispatchOnCallHangUp"); - - Collection listeners = getListeners(); - - for (IMXCallsManagerListener l : listeners) { - try { - l.onCallHangUp(call); - } catch (Exception e) { - Log.e(LOG_TAG, "dispatchOnCallHangUp " + e.getMessage(), e); - } - } - } - - /** - * dispatch the onVoipConferenceStarted event to the listeners - * - * @param roomId the room Id - */ - private void dispatchOnVoipConferenceStarted(String roomId) { - Log.d(LOG_TAG, "dispatchOnVoipConferenceStarted : " + roomId); - - Collection listeners = getListeners(); - - for (IMXCallsManagerListener l : listeners) { - try { - l.onVoipConferenceStarted(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "dispatchOnVoipConferenceStarted " + e.getMessage(), e); - } - } - } - - /** - * dispatch the onVoipConferenceFinished event to the listeners - * - * @param roomId the room Id - */ - private void dispatchOnVoipConferenceFinished(String roomId) { - Log.d(LOG_TAG, "onVoipConferenceFinished : " + roomId); - - Collection listeners = getListeners(); - - for (IMXCallsManagerListener l : listeners) { - try { - l.onVoipConferenceFinished(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "dispatchOnVoipConferenceFinished " + e.getMessage(), e); - } - } - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/MXCallsManagerListener.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/MXCallsManagerListener.java deleted file mode 100644 index ba6177f9..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/MXCallsManagerListener.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2015 OpenMarket 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.matrix.android.internal.legacy.call; - -import im.vector.matrix.android.internal.legacy.crypto.data.MXDeviceInfo; -import im.vector.matrix.android.internal.legacy.crypto.data.MXUsersDevicesMap; - -/** - * This class is the default implementation of MXCallsManagerListener - */ -public class MXCallsManagerListener implements IMXCallsManagerListener { - - @Override - public void onIncomingCall(IMXCall call, MXUsersDevicesMap unknownDevices) { - } - - @Override - public void onOutgoingCall(IMXCall call) { - } - - @Override - public void onCallHangUp(IMXCall call) { - } - - @Override - public void onVoipConferenceStarted(String roomId) { - } - - @Override - public void onVoipConferenceFinished(String roomId) { - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/MXChromeCall.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/MXChromeCall.java deleted file mode 100644 index b60ece1d..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/MXChromeCall.java +++ /dev/null @@ -1,687 +0,0 @@ -/* - * Copyright 2015 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.call; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.graphics.Color; -import android.os.Build; -import android.text.TextUtils; -import android.view.View; -import android.webkit.JavascriptInterface; -import android.webkit.PermissionRequest; -import android.webkit.WebChromeClient; -import android.webkit.WebSettings; -import android.webkit.WebView; -import android.webkit.WebViewClient; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; - -import im.vector.matrix.android.internal.legacy.MXSession; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.util.Timer; -import java.util.TimerTask; - -public class MXChromeCall extends MXCall { - private static final String LOG_TAG = MXChromeCall.class.getSimpleName(); - - private WebView mWebView = null; - private CallWebAppInterface mCallWebAppInterface = null; - - private boolean mIsIncomingPrepared = false; - - private JsonObject mCallInviteParams = null; - - private JsonArray mPendingCandidates = new JsonArray(); - - /** - * @return true if this stack can perform calls. - */ - public static boolean isSupported() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; - } - - // creator - public MXChromeCall(MXSession session, Context context, JsonElement turnServer) { - if (!isSupported()) { - throw new AssertionError("MXChromeCall : not supported with the current android version"); - } - - if (null == session) { - throw new AssertionError("MXChromeCall : session cannot be null"); - } - - if (null == context) { - throw new AssertionError("MXChromeCall : context cannot be null"); - } - - mCallId = "c" + System.currentTimeMillis(); - mSession = session; - mContext = context; - mTurnServer = turnServer; - } - - @Override - @SuppressLint("NewApi") - public void createCallView() { - super.createCallView(); - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - mWebView = new WebView(mContext); - mWebView.setBackgroundColor(Color.BLACK); - - // warn that the webview must be added in an activity/fragment - dispatchOnCallViewCreated(mWebView); - - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - mCallWebAppInterface = new CallWebAppInterface(); - mWebView.addJavascriptInterface(mCallWebAppInterface, "Android"); - - WebView.setWebContentsDebuggingEnabled(true); - WebSettings settings = mWebView.getSettings(); - - // Enable Javascript - settings.setJavaScriptEnabled(true); - - // Use WideViewport and Zoom out if there is no viewport defined - settings.setUseWideViewPort(true); - settings.setLoadWithOverviewMode(true); - - // Enable pinch to zoom without the zoom buttons - settings.setBuiltInZoomControls(true); - - // Allow use of Local Storage - settings.setDomStorageEnabled(true); - - settings.setAllowFileAccessFromFileURLs(true); - settings.setAllowUniversalAccessFromFileURLs(true); - - settings.setDisplayZoomControls(false); - - mWebView.setWebViewClient(new WebViewClient()); - - // AppRTC requires third party cookies to work - android.webkit.CookieManager cookieManager = android.webkit.CookieManager.getInstance(); - cookieManager.setAcceptThirdPartyCookies(mWebView, true); - - final String url = "file:///android_asset/www/call.html"; - mWebView.loadUrl(url); - - mWebView.setWebChromeClient(new WebChromeClient() { - @Override - public void onPermissionRequest(final PermissionRequest request) { - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - request.grant(request.getResources()); - } - }); - } - }); - } - }); - } - }); - } - - /** - * Start a call. - */ - @Override - public void placeCall(VideoLayoutConfiguration aLocalVideoPosition) { - super.placeCall(aLocalVideoPosition); - if (CALL_STATE_READY.equals(getCallState())) { - mIsIncoming = false; - - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - mWebView.loadUrl(mIsVideoCall ? "javascript:placeVideoCall()" : "javascript:placeVoiceCall()"); - } - }); - } - } - - /** - * Prepare a call reception. - * - * @param aCallInviteParams the invitation Event content - * @param aCallId the call ID - * @param aLocalVideoPosition position of the local video attendee - */ - @Override - public void prepareIncomingCall(final JsonObject aCallInviteParams, final String aCallId, VideoLayoutConfiguration aLocalVideoPosition) { - Log.d(LOG_TAG, "## prepareIncomingCall : call state " + getCallState()); - super.prepareIncomingCall(aCallInviteParams, aCallId, aLocalVideoPosition); - mCallId = aCallId; - - if (CALL_STATE_READY.equals(getCallState())) { - mIsIncoming = true; - - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - mWebView.loadUrl("javascript:initWithInvite('" + aCallId + "'," + aCallInviteParams.toString() + ")"); - mIsIncomingPrepared = true; - - mWebView.post(new Runnable() { - @Override - public void run() { - checkPendingCandidates(); - } - }); - } - }); - } else if (CALL_STATE_CREATED.equals(getCallState())) { - mCallInviteParams = aCallInviteParams; - - // detect call type from the sdp - try { - JsonObject offer = mCallInviteParams.get("offer").getAsJsonObject(); - JsonElement sdp = offer.get("sdp"); - String sdpValue = sdp.getAsString(); - setIsVideo(sdpValue.contains("m=video")); - } catch (Exception e) { - Log.e(LOG_TAG, "## prepareIncomingCall() ; " + e.getMessage(), e); - } - } - } - - /** - * The call has been detected as an incoming one. - * The application launched the dedicated activity and expects to launch the incoming call. - * - * @param aLocalVideoPosition local video position - */ - @Override - public void launchIncomingCall(VideoLayoutConfiguration aLocalVideoPosition) { - super.launchIncomingCall(aLocalVideoPosition); - if (CALL_STATE_READY.equals(getCallState())) { - prepareIncomingCall(mCallInviteParams, mCallId, null); - } - } - - /** - * The callee accepts the call. - * - * @param event the event - */ - private void onCallAnswer(final Event event) { - if (!CALL_STATE_CREATED.equals(getCallState()) && (null != mWebView)) { - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - mWebView.loadUrl("javascript:receivedAnswer(" + event.getContent().toString() + ")"); - } - }); - } - } - - /** - * The other call member hangs up the call. - * - * @param event the event - */ - private void onCallHangup(final Event event) { - if (!CALL_STATE_CREATED.equals(getCallState()) && (null != mWebView)) { - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - mWebView.loadUrl("javascript:onHangupReceived(" + event.getContent().toString() + ")"); - - mWebView.post(new Runnable() { - @Override - public void run() { - dispatchOnCallEnd(END_CALL_REASON_PEER_HANG_UP); - } - }); - } - }); - } - } - - /** - * A new Ice candidate is received - * - * @param candidates the ice candidates - */ - public void onNewCandidates(final JsonElement candidates) { - if (!CALL_STATE_CREATED.equals(getCallState()) && (null != mWebView)) { - mWebView.post(new Runnable() { - @Override - public void run() { - mWebView.loadUrl("javascript:gotRemoteCandidates(" + candidates.toString() + ")"); - } - }); - } - } - - /** - * Add ice candidates - * - * @param candidates ic candidates - */ - private void addCandidates(JsonArray candidates) { - if (mIsIncomingPrepared || !isIncoming()) { - onNewCandidates(candidates); - } else { - synchronized (LOG_TAG) { - mPendingCandidates.addAll(candidates); - } - } - } - - /** - * Some Ice candidates could have been received while creating the call view. - * Check if some of them have been defined. - */ - public void checkPendingCandidates() { - synchronized (LOG_TAG) { - onNewCandidates(mPendingCandidates); - mPendingCandidates = new JsonArray(); - } - } - - // events thread - - /** - * Manage the call events. - * - * @param event the call event. - */ - @Override - public void handleCallEvent(Event event) { - super.handleCallEvent(event); - - String eventType = event.getType(); - - if (event.isCallEvent()) { - // event from other member - if (!TextUtils.equals(event.getSender(), mSession.getMyUserId())) { - if (Event.EVENT_TYPE_CALL_ANSWER.equals(eventType) && !mIsIncoming) { - onCallAnswer(event); - } else if (Event.EVENT_TYPE_CALL_CANDIDATES.equals(eventType)) { - JsonArray candidates = event.getContentAsJsonObject().getAsJsonArray("candidates"); - addCandidates(candidates); - } else if (Event.EVENT_TYPE_CALL_HANGUP.equals(eventType)) { - onCallHangup(event); - } - } else if (Event.EVENT_TYPE_CALL_INVITE.equals(eventType)) { - // server echo : assume that the other device is ringing - mCallWebAppInterface.mCallState = IMXCall.CALL_STATE_RINGING; - - // warn in the UI thread - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - dispatchOnStateDidChange(mCallWebAppInterface.mCallState); - } - }); - - } else if (Event.EVENT_TYPE_CALL_ANSWER.equals(eventType)) { - // check if the call has not been answer in another device - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - // ring on this side - if (getCallState().equals(IMXCall.CALL_STATE_RINGING)) { - onAnsweredElsewhere(); - } - } - }); - - } - } - } - - // user actions - - /** - * The call is accepted. - */ - @Override - public void answer() { - super.answer(); - if (!CALL_STATE_CREATED.equals(getCallState()) && (null != mWebView)) { - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - mWebView.loadUrl("javascript:answerCall()"); - } - }); - } - } - - /** - * The call is hung up. - */ - @Override - public void hangup(String reason) { - super.hangup(reason); - - if (!CALL_STATE_CREATED.equals(getCallState()) && (null != mWebView)) { - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - mWebView.loadUrl("javascript:hangup()"); - } - }); - } else { - sendHangup(reason); - } - } - - // getters / setters - - /** - * @return the callstate (must be a CALL_STATE_XX value) - */ - @Override - public String getCallState() { - if (null != mCallWebAppInterface) { - return mCallWebAppInterface.mCallState; - } else { - return CALL_STATE_CREATED; - } - } - - /** - * @return the callView - */ - @Override - public View getCallView() { - return mWebView; - } - - /** - * @return the callView visibility - */ - @Override - public int getVisibility() { - if (null != mWebView) { - return mWebView.getVisibility(); - } else { - return View.GONE; - } - } - - /** - * Set the callview visibility - * - * @return true if the operation succeeds - */ - public boolean setVisibility(int visibility) { - if (null != mWebView) { - mWebView.setVisibility(visibility); - return true; - } - return false; - } - - @Override - public void onAnsweredElsewhere() { - super.onAnsweredElsewhere(); - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - mWebView.loadUrl("javascript:onAnsweredElsewhere()"); - } - }); - - dispatchAnsweredElsewhere(); - } - - // private class - private class CallWebAppInterface { - public String mCallState = CALL_STATE_CREATING_CALL_VIEW; - private Timer mCallTimeoutTimer = null; - - CallWebAppInterface() { - if (null == mCallingRoom) { - throw new AssertionError("MXChromeCall : room cannot be null"); - } - } - - // JS <-> android calls - @JavascriptInterface - public String wgetCallId() { - return mCallId; - } - - @JavascriptInterface - public String wgetRoomId() { - return mCallSignalingRoom.getRoomId(); - } - - @JavascriptInterface - public String wgetTurnServer() { - if (null != mTurnServer) { - return mTurnServer.toString(); - } else { - return null; - } - } - - @JavascriptInterface - public void wlog(String message) { - Log.d(LOG_TAG, "WebView Message : " + message); - } - - @JavascriptInterface - public void wCallError(String message) { - Log.e(LOG_TAG, "WebView error Message : " + message); - if ("ice_failed".equals(message)) { - dispatchOnCallError(CALL_ERROR_ICE_FAILED); - } else if ("user_media_failed".equals(message)) { - dispatchOnCallError(CALL_ERROR_CAMERA_INIT_FAILED); - } - } - - @JavascriptInterface - public void wOnStateUpdate(String jsstate) { - String nextState = null; - - if ("fledgling".equals(jsstate)) { - nextState = CALL_STATE_READY; - } else if ("wait_local_media".equals(jsstate)) { - nextState = CALL_STATE_WAIT_LOCAL_MEDIA; - } else if ("create_offer".equals(jsstate)) { - nextState = CALL_STATE_WAIT_CREATE_OFFER; - } else if ("invite_sent".equals(jsstate)) { - nextState = CALL_STATE_INVITE_SENT; - } else if ("ringing".equals(jsstate)) { - nextState = CALL_STATE_RINGING; - } else if ("create_answer".equals(jsstate)) { - nextState = CALL_STATE_CREATE_ANSWER; - } else if ("connecting".equals(jsstate)) { - nextState = CALL_STATE_CONNECTING; - } else if ("connected".equals(jsstate)) { - nextState = CALL_STATE_CONNECTED; - } else if ("ended".equals(jsstate)) { - nextState = CALL_STATE_ENDED; - } - - // is there any state update ? - if ((null != nextState) && !mCallState.equals(nextState)) { - mCallState = nextState; - - // warn in the UI thread - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - // call timeout management - if (CALL_STATE_CONNECTING.equals(mCallState) || CALL_STATE_CONNECTING.equals(mCallState)) { - if (null != mCallTimeoutTimer) { - mCallTimeoutTimer.cancel(); - mCallTimeoutTimer = null; - } - } - - dispatchOnStateDidChange(mCallState); - } - }); - } - } - - @JavascriptInterface - public void wOnLoaded() { - mCallState = CALL_STATE_READY; - - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - dispatchOnReady(); - } - }); - } - - private void sendHangup(final Event event) { - if (null != mCallTimeoutTimer) { - mCallTimeoutTimer.cancel(); - mCallTimeoutTimer = null; - } - - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - dispatchOnCallEnd(END_CALL_REASON_UNDEFINED); - } - }); - - mPendingEvents.clear(); - - mCallSignalingRoom.sendEvent(event, new ApiCallback() { - @Override - public void onSuccess(Void info) { - } - - @Override - public void onNetworkError(Exception e) { - // try again - sendHangup(event); - } - - @Override - public void onMatrixError(MatrixError e) { - } - - @Override - public void onUnexpectedError(Exception e) { - } - }); - } - - @JavascriptInterface - public void wSendEvent(final String roomId, final String eventType, final String jsonContent) { - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - try { - boolean addIt = true; - JsonObject content = (JsonObject) new JsonParser().parse(jsonContent); - - // merge candidates - if (TextUtils.equals(eventType, Event.EVENT_TYPE_CALL_CANDIDATES) && (mPendingEvents.size() > 0)) { - try { - Event lastEvent = mPendingEvents.get(mPendingEvents.size() - 1); - - if (TextUtils.equals(lastEvent.getType(), Event.EVENT_TYPE_CALL_CANDIDATES)) { - JsonObject lastContent = lastEvent.getContentAsJsonObject(); - - JsonArray lastContentCandidates = lastContent.get("candidates").getAsJsonArray(); - JsonArray newContentCandidates = content.get("candidates").getAsJsonArray(); - - Log.d(LOG_TAG, "Merge candidates from " + lastContentCandidates.size() - + " to " + (lastContentCandidates.size() + newContentCandidates.size() + " items.")); - - lastContentCandidates.addAll(newContentCandidates); - - lastContent.remove("candidates"); - lastContent.add("candidates", lastContentCandidates); - addIt = false; - } - } catch (Exception e) { - Log.e(LOG_TAG, "## wSendEvent() ; " + e.getMessage(), e); - } - } - - if (addIt) { - Event event = new Event(eventType, content, mSession.getCredentials().getUserId(), mCallSignalingRoom.getRoomId()); - - if (null != event) { - // receive an hangup -> close the window asap - if (TextUtils.equals(eventType, Event.EVENT_TYPE_CALL_HANGUP)) { - sendHangup(event); - } else { - mPendingEvents.add(event); - } - - // the calleee has 30s to answer to call - if (TextUtils.equals(eventType, Event.EVENT_TYPE_CALL_INVITE)) { - try { - mCallTimeoutTimer = new Timer(); - mCallTimeoutTimer.schedule(new TimerTask() { - @Override - public void run() { - try { - if (getCallState().equals(IMXCall.CALL_STATE_RINGING) - || getCallState().equals(IMXCall.CALL_STATE_INVITE_SENT)) { - dispatchOnCallError(CALL_ERROR_USER_NOT_RESPONDING); - hangup(null); - } - - // cancel the timer - mCallTimeoutTimer.cancel(); - mCallTimeoutTimer = null; - } catch (Exception e) { - Log.e(LOG_TAG, "## wSendEvent() ; " + e.getMessage(), e); - } - } - }, CALL_TIMEOUT_MS); - } catch (Throwable throwable) { - if (null != mCallTimeoutTimer) { - mCallTimeoutTimer.cancel(); - mCallTimeoutTimer = null; - } - Log.e(LOG_TAG, "## wSendEvent() ; " + throwable.getMessage(), throwable); - } - } - } - } - - // send events - sendNextEvent(); - - } catch (Exception e) { - Log.e(LOG_TAG, "## wSendEvent() ; " + e.getMessage(), e); - } - } - }); - } - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/MXWebRtcCall.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/MXWebRtcCall.java deleted file mode 100644 index 902e8b95..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/MXWebRtcCall.java +++ /dev/null @@ -1,1733 +0,0 @@ -/* - * Copyright 2015 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.call; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.support.v4.content.ContextCompat; -import android.text.TextUtils; -import android.util.DisplayMetrics; -import android.view.View; -import android.widget.RelativeLayout; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.oney.WebRTCModule.EglUtils; - -import im.vector.matrix.android.internal.legacy.MXSession; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.util.Log; -import org.webrtc.AudioSource; -import org.webrtc.AudioTrack; -import org.webrtc.Camera1Enumerator; -import org.webrtc.Camera2Enumerator; -import org.webrtc.CameraEnumerator; -import org.webrtc.CameraVideoCapturer; -import org.webrtc.DataChannel; -import org.webrtc.EglBase; -import org.webrtc.IceCandidate; -import org.webrtc.MediaConstraints; -import org.webrtc.MediaStream; -import org.webrtc.PeerConnection; -import org.webrtc.PeerConnectionFactory; -import org.webrtc.RtpReceiver; -import org.webrtc.SdpObserver; -import org.webrtc.SessionDescription; -import org.webrtc.VideoSource; -import org.webrtc.VideoTrack; - -import java.util.ArrayList; -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; - -public class MXWebRtcCall extends MXCall { - private static final String LOG_TAG = MXWebRtcCall.class.getSimpleName(); - - private static final String VIDEO_TRACK_ID = "ARDAMSv0"; - private static final String AUDIO_TRACK_ID = "ARDAMSa0"; - - private static final int DEFAULT_WIDTH = 640; - private static final int DEFAULT_HEIGHT = 360; - private static final int DEFAULT_FPS = 30; - - private static final int CAMERA_TYPE_FRONT = 1; - private static final int CAMERA_TYPE_REAR = 2; - private static final int CAMERA_TYPE_UNDEFINED = -1; - - static private PeerConnectionFactory mPeerConnectionFactory = null; - static private String mFrontCameraName = null; - static private String mBackCameraName = null; - static private CameraVideoCapturer mCameraVideoCapturer = null; - - private RelativeLayout mCallView = null; - - private boolean mIsCameraSwitched; - private boolean mIsCameraUnplugged = false; - private VideoSource mVideoSource = null; - private VideoTrack mLocalVideoTrack = null; - private AudioSource mAudioSource = null; - private AudioTrack mLocalAudioTrack = null; - private MediaStream mLocalMediaStream = null; - - private VideoTrack mRemoteVideoTrack = null; - private PeerConnection mPeerConnection = null; - - // default value - private String mCallState = CALL_STATE_CREATED; - - private boolean mUsingLargeLocalRenderer = true; - private MXWebRtcView mFullScreenRTCView = null; - private MXWebRtcView mPipRTCView = null; - - private static boolean mIsInitialized = false; - // null -> not initialized - // true / false for the supported status - private static Boolean mIsSupported; - - // candidate management - private boolean mIsIncomingPrepared = false; - private JsonArray mPendingCandidates = new JsonArray(); - - private JsonObject mCallInviteParams = null; - private int mCameraInUse = CAMERA_TYPE_UNDEFINED; - - private boolean mIsAnswered = false; - - /** - * @param context the context - * @return true if this stack can perform calls. - */ - public static boolean isSupported(Context context) { - if (null == mIsSupported) { - initializeAndroidGlobals(context.getApplicationContext()); - - Log.d(LOG_TAG, "isSupported " + mIsSupported); - } - - return mIsSupported; - } - - /** - * Tells if the camera2 Api is supported - * - * @param context the context - * @return true if the Camera2 API is supported - */ - private static boolean useCamera2(Context context) { - return Camera2Enumerator.isSupported(context); - } - - /** - * Test if the camera is not used by another app. - * It is used to prevent crashes at org.webrtc.Camera1Session.create(Camera1Session.java:80) - * when the front camera is not available. - * - * @param context the context - * @param isFrontOne true if the camera is the - * @return true if the camera is used. - */ - @SuppressLint("Deprecation") - private static boolean isCameraInUse(Context context, boolean isFrontOne) { - boolean isUsed = false; - - if (!useCamera2(context)) { - int cameraId = -1; - int numberOfCameras = android.hardware.Camera.getNumberOfCameras(); - for (int i = 0; i < numberOfCameras; i++) { - android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo(); - android.hardware.Camera.getCameraInfo(i, info); - - if ((info.facing == android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT) && isFrontOne) { - cameraId = i; - break; - } else if ((info.facing == android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK) && !isFrontOne) { - cameraId = i; - break; - } - } - - if (cameraId >= 0) { - android.hardware.Camera c = null; - try { - c = android.hardware.Camera.open(cameraId); - } catch (Exception e) { - Log.e(LOG_TAG, "## isCameraInUse() : failed " + e.getMessage(), e); - } finally { - isUsed = (null == c); - if (c != null) { - c.release(); - } - } - } - } - - return isUsed; - } - - /** - * Get a camera enumerator - * - * @param context the context - * @return the camera enumerator - */ - private static CameraEnumerator getCameraEnumerator(Context context) { - if (useCamera2(context)) { - return new Camera2Enumerator(context); - } else { - return new Camera1Enumerator(false); - } - } - - /** - * Constructor - * - * @param session the session - * @param context the context - * @param turnServer the turn server - */ - public MXWebRtcCall(MXSession session, Context context, JsonElement turnServer) { - if (!isSupported(context)) { - throw new AssertionError("MXWebRtcCall : not supported with the current android version"); - } - - if (null == session) { - throw new AssertionError("MXWebRtcCall : session cannot be null"); - } - - if (null == context) { - throw new AssertionError("MXWebRtcCall : context cannot be null"); - } - - Log.d(LOG_TAG, "MXWebRtcCall constructor " + turnServer); - - mCallId = "c" + System.currentTimeMillis(); - mSession = session; - mContext = context; - mTurnServer = turnServer; - } - - /** - * Initialize globals - */ - private static void initializeAndroidGlobals(Context context) { - if (!mIsInitialized) { - try { - mIsInitialized = PeerConnectionFactory.initializeAndroidGlobals( - context, - true, // enable audio initializing - true, // enable video initializing - true // enable hardware acceleration - ); - - PeerConnectionFactory.initializeFieldTrials(null); - - mIsSupported = true; - Log.d(LOG_TAG, "## initializeAndroidGlobals(): mIsInitialized=" + mIsInitialized); - } catch (Throwable e) { - Log.e(LOG_TAG, "## initializeAndroidGlobals(): Exception Msg=" + e.getMessage(), e); - mIsInitialized = true; - mIsSupported = false; - } - } - } - - /** - * Create the callviews - */ - @Override - public void createCallView() { - super.createCallView(); - - if ((null != mIsSupported) && mIsSupported) { - Log.d(LOG_TAG, "++ createCallView()"); - - dispatchOnStateDidChange(CALL_STATE_CREATING_CALL_VIEW); - mUIThreadHandler.postDelayed(new Runnable() { - @Override - public void run() { - mCallView = new RelativeLayout(mContext); - mCallView.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, - RelativeLayout.LayoutParams.MATCH_PARENT)); - mCallView.setBackgroundColor(ContextCompat.getColor(mContext, android.R.color.black)); - mCallView.setVisibility(View.GONE); - - dispatchOnCallViewCreated(mCallView); - - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - dispatchOnStateDidChange(CALL_STATE_READY); - dispatchOnReady(); - } - }); - } - }, 10); - } - } - - /** - * The connection is terminated - * - * @param endCallReasonId the reason of the call ending - */ - private void terminate(final int endCallReasonId) { - Log.d(LOG_TAG, "## terminate(): reason= " + endCallReasonId); - - if (isCallEnded()) { - return; - } - - dispatchOnStateDidChange(CALL_STATE_ENDED); - - boolean isPeerConnectionFactoryAllowed = false; - - if (null != mPeerConnection) { - mPeerConnection.dispose(); - mPeerConnection = null; - // the call has been initialized so mPeerConnectionFactory can be released - isPeerConnectionFactoryAllowed = true; - } - - if (null != mCameraVideoCapturer) { - mCameraVideoCapturer.dispose(); - mCameraVideoCapturer = null; - } - - if (null != mVideoSource) { - mVideoSource.dispose(); - mVideoSource = null; - } - - if (null != mAudioSource) { - mAudioSource.dispose(); - mAudioSource = null; - } - - // mPeerConnectionFactory is static so it might be used by another call - // so we test that the current has been created - if (isPeerConnectionFactoryAllowed && (null != mPeerConnectionFactory)) { - mPeerConnectionFactory.dispose(); - mPeerConnectionFactory = null; - } - - if (null != mCallView) { - final View fCallView = mCallView; - - fCallView.post(new Runnable() { - @Override - public void run() { - fCallView.setVisibility(View.GONE); - } - }); - - mCallView = null; - } - - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - dispatchOnCallEnd(endCallReasonId); - } - }); - } - - /** - * Send the invite event - * - * @param sessionDescription the session description. - */ - private void sendInvite(final SessionDescription sessionDescription) { - // check if the call has not been killed - if (isCallEnded()) { - Log.d(LOG_TAG, "## sendInvite(): isCallEnded"); - return; - } - - Log.d(LOG_TAG, "## sendInvite()"); - - // build the invitation event - JsonObject inviteContent = new JsonObject(); - inviteContent.addProperty("version", 0); - inviteContent.addProperty("call_id", mCallId); - inviteContent.addProperty("lifetime", CALL_TIMEOUT_MS); - - JsonObject offerContent = new JsonObject(); - offerContent.addProperty("sdp", sessionDescription.description); - offerContent.addProperty("type", sessionDescription.type.canonicalForm()); - inviteContent.add("offer", offerContent); - - Event event = new Event(Event.EVENT_TYPE_CALL_INVITE, inviteContent, mSession.getCredentials().getUserId(), mCallSignalingRoom.getRoomId()); - - mPendingEvents.add(event); - - try { - mCallTimeoutTimer = new Timer(); - mCallTimeoutTimer.schedule(new TimerTask() { - @Override - public void run() { - try { - if (getCallState().equals(IMXCall.CALL_STATE_RINGING) || getCallState().equals(IMXCall.CALL_STATE_INVITE_SENT)) { - Log.d(LOG_TAG, "sendInvite : CALL_ERROR_USER_NOT_RESPONDING"); - dispatchOnCallError(CALL_ERROR_USER_NOT_RESPONDING); - hangup(null); - } - - // cancel the timer - mCallTimeoutTimer.cancel(); - mCallTimeoutTimer = null; - } catch (Exception e) { - Log.e(LOG_TAG, "## sendInvite(): Exception Msg= " + e.getMessage(), e); - } - } - }, CALL_TIMEOUT_MS); - } catch (Throwable throwable) { - Log.e(LOG_TAG, "## sendInvite(): failed " + throwable.getMessage(), throwable); - if (null != mCallTimeoutTimer) { - mCallTimeoutTimer.cancel(); - mCallTimeoutTimer = null; - } - } - - sendNextEvent(); - } - - /** - * Send the answer event - * - * @param sessionDescription the session description - */ - private void sendAnswer(final SessionDescription sessionDescription) { - // check if the call has not been killed - if (isCallEnded()) { - Log.d(LOG_TAG, "sendAnswer isCallEnded"); - return; - } - - Log.d(LOG_TAG, "sendAnswer"); - - // build the invitation event - JsonObject answerContent = new JsonObject(); - answerContent.addProperty("version", 0); - answerContent.addProperty("call_id", mCallId); - answerContent.addProperty("lifetime", CALL_TIMEOUT_MS); - - JsonObject offerContent = new JsonObject(); - offerContent.addProperty("sdp", sessionDescription.description); - offerContent.addProperty("type", sessionDescription.type.canonicalForm()); - answerContent.add("answer", offerContent); - - Event event = new Event(Event.EVENT_TYPE_CALL_ANSWER, answerContent, mSession.getCredentials().getUserId(), mCallSignalingRoom.getRoomId()); - mPendingEvents.add(event); - sendNextEvent(); - - mIsAnswered = true; - } - - @Override - public void updateLocalVideoRendererPosition(VideoLayoutConfiguration aConfigurationToApply) { - super.updateLocalVideoRendererPosition(aConfigurationToApply); - try { - updateWebRtcViewLayout(mPipRTCView, aConfigurationToApply); - } catch (Exception e) { - Log.e(LOG_TAG, "## updateLocalVideoRendererPosition(): Exception Msg=" + e.getMessage(), e); - } - } - - @Override - public boolean isSwitchCameraSupported() { - String[] deviceNames = getCameraEnumerator(mContext).getDeviceNames(); - return (null != deviceNames) && (0 != deviceNames.length); - } - - @Override - public boolean switchRearFrontCamera() { - if ((null != mCameraVideoCapturer) && (isSwitchCameraSupported())) { - try { - mCameraVideoCapturer.switchCamera(null); - - // toggle the video capturer instance - if (CAMERA_TYPE_FRONT == mCameraInUse) { - mCameraInUse = CAMERA_TYPE_REAR; - } else { - mCameraInUse = CAMERA_TYPE_FRONT; - } - - // compute camera switch new status - mIsCameraSwitched = !mIsCameraSwitched; - - return true; - } catch (Exception e) { - Log.e(LOG_TAG, "## switchRearFrontCamera(): failed " + e.getMessage(), e); - } - } else { - Log.w(LOG_TAG, "## switchRearFrontCamera(): failure - invalid values"); - } - return false; - } - - @Override - public void muteVideoRecording(boolean muteValue) { - Log.d(LOG_TAG, "## muteVideoRecording(): muteValue=" + muteValue); - - if (!isCallEnded()) { - if (null != mLocalVideoTrack) { - mLocalVideoTrack.setEnabled(!muteValue); - } else { - Log.d(LOG_TAG, "## muteVideoRecording(): failure - invalid value"); - } - } else { - Log.d(LOG_TAG, "## muteVideoRecording(): the call is ended"); - } - } - - @Override - public boolean isVideoRecordingMuted() { - boolean isMuted = false; - - if (!isCallEnded()) { - if (null != mLocalVideoTrack) { - isMuted = !mLocalVideoTrack.enabled(); - } else { - Log.w(LOG_TAG, "## isVideoRecordingMuted(): failure - invalid value"); - } - - Log.d(LOG_TAG, "## isVideoRecordingMuted() = " + isMuted); - } else { - Log.d(LOG_TAG, "## isVideoRecordingMuted() : the call is ended"); - } - - return isMuted; - } - - @Override - public boolean isCameraSwitched() { - return mIsCameraSwitched; - } - - /** - * create the local stream - */ - private void createLocalStream() { - Log.d(LOG_TAG, "## createLocalStream(): IN"); - - // check there is at least one stream to start a call - if ((null == mLocalVideoTrack) && (null == mLocalAudioTrack)) { - Log.d(LOG_TAG, "## createLocalStream(): CALL_ERROR_CALL_INIT_FAILED"); - - dispatchOnCallError(CALL_ERROR_CALL_INIT_FAILED); - hangup("no_stream"); - terminate(IMXCall.END_CALL_REASON_UNDEFINED); - return; - } - - // create our local stream to add our audio and video tracks - mLocalMediaStream = mPeerConnectionFactory.createLocalMediaStream("ARDAMS"); - // add video track to local stream - if (null != mLocalVideoTrack) { - mLocalMediaStream.addTrack(mLocalVideoTrack); - } - // add audio track to local stream - if (null != mLocalAudioTrack) { - mLocalMediaStream.addTrack(mLocalAudioTrack); - } - - if (null != mFullScreenRTCView) { - mFullScreenRTCView.setStream(mLocalMediaStream); - mFullScreenRTCView.setVisibility(View.VISIBLE); - } - - // build ICE servers list - List iceServers = new ArrayList<>(); - - if (null != mTurnServer) { - try { - String username = null; - String password = null; - JsonObject object = mTurnServer.getAsJsonObject(); - - if (object.has("username")) { - username = object.get("username").getAsString(); - } - - if (object.has("password")) { - password = object.get("password").getAsString(); - } - - JsonArray uris = object.get("uris").getAsJsonArray(); - - for (int index = 0; index < uris.size(); index++) { - String url = uris.get(index).getAsString(); - - if ((null != username) && (null != password)) { - iceServers.add(new PeerConnection.IceServer(url, username, password)); - } else { - iceServers.add(new PeerConnection.IceServer(url)); - } - } - } catch (Exception e) { - Log.e(LOG_TAG, "## createLocalStream(): Exception in ICE servers list Msg=" + e.getMessage(), e); - } - } - - Log.d(LOG_TAG, "## createLocalStream(): " + iceServers.size() + " known ice servers"); - - // define at least on server - if (iceServers.isEmpty()) { - Log.d(LOG_TAG, "## createLocalStream(): use the default google server"); - iceServers.add(new PeerConnection.IceServer("stun:stun.l.google.com:19302")); - } - - // define constraints - MediaConstraints pcConstraints = new MediaConstraints(); - pcConstraints.optional.add(new MediaConstraints.KeyValuePair("RtpDataChannels", "true")); - - // start connecting to the other peer by creating the peer connection - mPeerConnection = mPeerConnectionFactory.createPeerConnection( - iceServers, - pcConstraints, - new PeerConnection.Observer() { - @Override - public void onSignalingChange(PeerConnection.SignalingState signalingState) { - Log.d(LOG_TAG, "## mPeerConnection creation: onSignalingChange state=" + signalingState); - } - - @Override - public void onIceConnectionChange(final PeerConnection.IceConnectionState iceConnectionState) { - Log.d(LOG_TAG, "## mPeerConnection creation: onIceConnectionChange " + iceConnectionState); - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - if (iceConnectionState == PeerConnection.IceConnectionState.CONNECTED) { - if ((null != mLocalVideoTrack) && mUsingLargeLocalRenderer && isVideo()) { - mLocalVideoTrack.setEnabled(false); - - // in conference call, there is no local preview, - // the local attendee video is sent by the server among the others conference attendees. - if (!isConference()) { - // add local preview, only for 1:1 call - //mLocalVideoTrack.addRenderer(mSmallLocalRenderer); - mPipRTCView.setStream(mLocalMediaStream); - mPipRTCView.setVisibility(View.VISIBLE); - - // to be able to display the avatar video above the large one - mPipRTCView.setZOrder(1); - } - - mLocalVideoTrack.setEnabled(true); - mUsingLargeLocalRenderer = false; - - mCallView.post(new Runnable() { - @Override - public void run() { - if (null != mCallView) { - mCallView.invalidate(); - } - } - }); - } - - dispatchOnStateDidChange(IMXCall.CALL_STATE_CONNECTED); - } - // theses states are ignored - // only the matrix hangup event is managed - /*else if (iceConnectionState == PeerConnection.IceConnectionState.DISCONNECTED) { - // TODO warn the user ? - hangup(null); - } else if (iceConnectionState == PeerConnection.IceConnectionState.CLOSED) { - // TODO warn the user ? - terminate(); - }*/ - else if (iceConnectionState == PeerConnection.IceConnectionState.FAILED) { - dispatchOnCallError(CALL_ERROR_ICE_FAILED); - hangup("ice_failed"); - } - } - }); - } - - @Override - public void onIceConnectionReceivingChange(boolean var1) { - Log.d(LOG_TAG, "## mPeerConnection creation: onIceConnectionReceivingChange " + var1); - } - - @Override - public void onIceCandidatesRemoved(IceCandidate[] var1) { - Log.d(LOG_TAG, "## mPeerConnection creation: onIceCandidatesRemoved " + var1); - } - - @Override - public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) { - Log.d(LOG_TAG, "## mPeerConnection creation: onIceGatheringChange " + iceGatheringState); - } - - @Override - public void onAddTrack(RtpReceiver var1, MediaStream[] var2) { - Log.d(LOG_TAG, "## mPeerConnection creation: onAddTrack " + var1 + " -- " + var2); - } - - @Override - public void onIceCandidate(final IceCandidate iceCandidate) { - Log.d(LOG_TAG, "## mPeerConnection creation: onIceCandidate " + iceCandidate); - - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - if (!isCallEnded()) { - JsonObject content = new JsonObject(); - content.addProperty("version", 0); - content.addProperty("call_id", mCallId); - - JsonArray candidates = new JsonArray(); - JsonObject cand = new JsonObject(); - cand.addProperty("sdpMLineIndex", iceCandidate.sdpMLineIndex); - cand.addProperty("sdpMid", iceCandidate.sdpMid); - cand.addProperty("candidate", iceCandidate.sdp); - candidates.add(cand); - content.add("candidates", candidates); - - boolean addIt = true; - - // merge candidates - if (mPendingEvents.size() > 0) { - try { - Event lastEvent = mPendingEvents.get(mPendingEvents.size() - 1); - - if (TextUtils.equals(lastEvent.getType(), Event.EVENT_TYPE_CALL_CANDIDATES)) { - // return the content cast as a JsonObject - // it is not a copy - JsonObject lastContent = lastEvent.getContentAsJsonObject(); - - JsonArray lastContentCandidates = lastContent.get("candidates").getAsJsonArray(); - JsonArray newContentCandidates = content.get("candidates").getAsJsonArray(); - - Log.d(LOG_TAG, "Merge candidates from " + lastContentCandidates.size() - + " to " + (lastContentCandidates.size() + newContentCandidates.size() + " items.")); - - lastContentCandidates.addAll(newContentCandidates); - - // replace the candidates list - lastContent.remove("candidates"); - lastContent.add("candidates", lastContentCandidates); - - // don't need to save anything, lastContent is a reference not a copy - addIt = false; - } - } catch (Exception e) { - Log.e(LOG_TAG, "## createLocalStream(): createPeerConnection - onIceCandidate() Exception Msg=" - + e.getMessage(), e); - } - } - - if (addIt) { - Event event = new Event(Event.EVENT_TYPE_CALL_CANDIDATES, content, mSession.getCredentials().getUserId(), - mCallSignalingRoom.getRoomId()); - - mPendingEvents.add(event); - sendNextEvent(); - } - } - } - }); - } - - @Override - public void onAddStream(final MediaStream mediaStream) { - Log.d(LOG_TAG, "## mPeerConnection creation: onAddStream " + mediaStream); - - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - if ((mediaStream.videoTracks.size() == 1) && !isCallEnded()) { - mRemoteVideoTrack = mediaStream.videoTracks.get(0); - mRemoteVideoTrack.setEnabled(true); - mFullScreenRTCView.setStream(mediaStream); - mFullScreenRTCView.setVisibility(View.VISIBLE); - } - } - }); - } - - @Override - public void onRemoveStream(final MediaStream mediaStream) { - Log.d(LOG_TAG, "## mPeerConnection creation: onRemoveStream " + mediaStream); - - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - if (null != mRemoteVideoTrack) { - mRemoteVideoTrack.dispose(); - mRemoteVideoTrack = null; - mediaStream.videoTracks.get(0).dispose(); - } - } - }); - - } - - @Override - public void onDataChannel(DataChannel dataChannel) { - Log.d(LOG_TAG, "## mPeerConnection creation: onDataChannel " + dataChannel); - } - - @Override - public void onRenegotiationNeeded() { - Log.d(LOG_TAG, "## mPeerConnection creation: onRenegotiationNeeded"); - } - }); - - if (null == mPeerConnection) { - dispatchOnCallError(CALL_ERROR_ICE_FAILED); - hangup("cannot create peer connection"); - return; - } - - // send our local video and audio stream to make it seen by the other part - mPeerConnection.addStream(mLocalMediaStream); - - MediaConstraints constraints = new MediaConstraints(); - constraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true")); - constraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveVideo", isVideo() ? "true" : "false")); - - // call createOffer only for outgoing calls - if (!isIncoming()) { - Log.d(LOG_TAG, "## createLocalStream(): !isIncoming() -> createOffer"); - - mPeerConnection.createOffer(new SdpObserver() { - @Override - public void onCreateSuccess(SessionDescription sessionDescription) { - Log.d(LOG_TAG, "createOffer onCreateSuccess"); - - final SessionDescription sdp = new SessionDescription(sessionDescription.type, sessionDescription.description); - - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - if (mPeerConnection != null) { - // must be done to before sending the invitation message - mPeerConnection.setLocalDescription(new SdpObserver() { - @Override - public void onCreateSuccess(SessionDescription sessionDescription) { - Log.d(LOG_TAG, "setLocalDescription onCreateSuccess"); - } - - @Override - public void onSetSuccess() { - Log.d(LOG_TAG, "setLocalDescription onSetSuccess"); - sendInvite(sdp); - dispatchOnStateDidChange(IMXCall.CALL_STATE_INVITE_SENT); - } - - @Override - public void onCreateFailure(String s) { - Log.e(LOG_TAG, "setLocalDescription onCreateFailure " + s); - dispatchOnCallError(CALL_ERROR_CAMERA_INIT_FAILED); - hangup(null); - } - - @Override - public void onSetFailure(String s) { - Log.e(LOG_TAG, "setLocalDescription onSetFailure " + s); - dispatchOnCallError(CALL_ERROR_CAMERA_INIT_FAILED); - hangup(null); - } - }, sdp); - } - } - }); - } - - @Override - public void onSetSuccess() { - Log.d(LOG_TAG, "createOffer onSetSuccess"); - } - - @Override - public void onCreateFailure(String s) { - Log.d(LOG_TAG, "createOffer onCreateFailure " + s); - dispatchOnCallError(CALL_ERROR_CAMERA_INIT_FAILED); - } - - @Override - public void onSetFailure(String s) { - Log.d(LOG_TAG, "createOffer onSetFailure " + s); - dispatchOnCallError(CALL_ERROR_CAMERA_INIT_FAILED); - } - }, constraints); - - dispatchOnStateDidChange(IMXCall.CALL_STATE_WAIT_CREATE_OFFER); - } - } - - /** - * @return true if the device has a camera device - */ - private boolean hasCameraDevice() { - CameraEnumerator enumerator = getCameraEnumerator(mContext); - String[] deviceNames = enumerator.getDeviceNames(); - int cameraCount = 0; - - mBackCameraName = mFrontCameraName = null; - - if (null != deviceNames) { - for (String deviceName : deviceNames) { - if (enumerator.isFrontFacing(deviceName) && !isCameraInUse(mContext, true)) { - mFrontCameraName = deviceName; - } else if (enumerator.isBackFacing(deviceName) && !isCameraInUse(mContext, false)) { - mBackCameraName = deviceName; - } - } - - cameraCount = deviceNames.length; - } - - Log.d(LOG_TAG, "hasCameraDevice(): camera number= " + cameraCount); - Log.d(LOG_TAG, "hasCameraDevice(): frontCameraName=" + mFrontCameraName + " backCameraName=" + mBackCameraName); - - return (null != mFrontCameraName) || (null != mBackCameraName); - } - - /** - * Create the video capturer - * - * @param cameraName the selected camera name - * @return the video capturer - */ - private CameraVideoCapturer createVideoCapturer(String cameraName) { - CameraVideoCapturer cameraVideoCapturer = null; - - CameraEnumerator camerasEnumerator = getCameraEnumerator(mContext); - final String[] deviceNames = camerasEnumerator.getDeviceNames(); - - - if ((null != deviceNames) && (deviceNames.length > 0)) { - for (String name : deviceNames) { - if (name.equals(cameraName)) { - cameraVideoCapturer = camerasEnumerator.createCapturer(name, null); - if (null != cameraVideoCapturer) { - break; - } - } - } - - if (null == cameraVideoCapturer) { - cameraVideoCapturer = camerasEnumerator.createCapturer(deviceNames[0], null); - } - } - - return cameraVideoCapturer; - } - - /** - * Create the local video stack - */ - private void createVideoTrack() { // permission crash - Log.d(LOG_TAG, "createVideoTrack"); - - // create the local renderer only if there is a camera on the device - if (hasCameraDevice()) { - try { - if (null != mCameraVideoCapturer) { - mCameraVideoCapturer.dispose(); - mCameraVideoCapturer = null; - } - - if (null != mFrontCameraName) { - mCameraVideoCapturer = createVideoCapturer(mFrontCameraName); - - if (null == mCameraVideoCapturer) { - Log.e(LOG_TAG, "Cannot create Video Capturer from front camera"); - } else { - mCameraInUse = CAMERA_TYPE_FRONT; - } - } - - if ((null == mCameraVideoCapturer) && (null != mBackCameraName)) { - mCameraVideoCapturer = createVideoCapturer(mBackCameraName); - - if (null == mCameraVideoCapturer) { - Log.e(LOG_TAG, "Cannot create Video Capturer from back camera"); - } else { - mCameraInUse = CAMERA_TYPE_REAR; - } - } - } catch (Exception ex2) { - // catch exception due to Android M permissions, when - // a call is received and the permissions (camera and audio) were not yet granted - Log.e(LOG_TAG, "createVideoTrack(): Exception Msg=" + ex2.getMessage(), ex2); - } - - if (null != mCameraVideoCapturer) { - Log.d(LOG_TAG, "createVideoTrack find a video capturer"); - - try { - mVideoSource = mPeerConnectionFactory.createVideoSource(mCameraVideoCapturer); - mCameraVideoCapturer.startCapture(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FPS); - - mLocalVideoTrack = mPeerConnectionFactory.createVideoTrack(VIDEO_TRACK_ID, mVideoSource); - mLocalVideoTrack.setEnabled(true); - } catch (Exception e) { - Log.e(LOG_TAG, "createVideoSource fails with exception " + e.getMessage(), e); - - mLocalVideoTrack = null; - - if (null != mVideoSource) { - mVideoSource.dispose(); - mVideoSource = null; - } - } - } else { - Log.e(LOG_TAG, "## createVideoTrack(): Cannot create Video Capturer - no camera available"); - } - } - } - - /** - * Create the local audio stack - */ - private void createAudioTrack() { - Log.d(LOG_TAG, "createAudioTrack"); - - MediaConstraints audioConstraints = new MediaConstraints(); - - // add all existing audio filters to avoid having echos - audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googEchoCancellation", "true")); - audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googEchoCancellation2", "true")); - audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googDAEchoCancellation", "true")); - - audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googTypingNoiseDetection", "true")); - - audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googAutoGainControl", "true")); - audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googAutoGainControl2", "true")); - - audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googNoiseSuppression", "true")); - audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googNoiseSuppression2", "true")); - - audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googAudioMirroring", "false")); - audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googHighpassFilter", "true")); - - mAudioSource = mPeerConnectionFactory.createAudioSource(audioConstraints); - mLocalAudioTrack = mPeerConnectionFactory.createAudioTrack(AUDIO_TRACK_ID, mAudioSource); - } - - /** - * Update the webRtcView layout - * - * @param webRTCView the view - * @param aLocalVideoPosition the video configuration - */ - private void updateWebRtcViewLayout(MXWebRtcView webRTCView, VideoLayoutConfiguration aLocalVideoPosition) { - if (null != webRTCView) { - final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics(); - - int screenWidth = (aLocalVideoPosition.mDisplayWidth > 0) ? aLocalVideoPosition.mDisplayWidth : displayMetrics.widthPixels; - int screenHeight = (aLocalVideoPosition.mDisplayHeight > 0) ? aLocalVideoPosition.mDisplayHeight : displayMetrics.heightPixels; - - int x = screenWidth * aLocalVideoPosition.mX / 100; - int y = screenHeight * aLocalVideoPosition.mY / 100; - int width = screenWidth * aLocalVideoPosition.mWidth / 100; - int height = screenHeight * aLocalVideoPosition.mHeight / 100; - - RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(width, height); - params.leftMargin = x; - params.topMargin = y; - webRTCView.setLayoutParams(params); - } - } - - /** - * Initialize the call UI - * - * @param callInviteParams the invite params - * @param aLocalVideoPosition position of the local video attendee - */ - @SuppressLint("deprecation") - private void initCallUI(final JsonObject callInviteParams, VideoLayoutConfiguration aLocalVideoPosition) { - Log.d(LOG_TAG, "## initCallUI(): IN"); - - if (isCallEnded()) { - Log.w(LOG_TAG, "## initCallUI(): skipped due to call is ended"); - return; - } - - if (isVideo()) { - Log.d(LOG_TAG, "## initCallUI(): building UI video call"); - try { - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - if (null == mPeerConnectionFactory) { - Log.d(LOG_TAG, "## initCallUI(): video call and no mPeerConnectionFactory"); - - mPeerConnectionFactory = new PeerConnectionFactory(null); - - // Initialize EGL contexts required for HW acceleration. - EglBase.Context eglContext = EglUtils.getRootEglBaseContext(); - if (eglContext != null) { - mPeerConnectionFactory.setVideoHwAccelerationOptions(eglContext, eglContext); - } - - createVideoTrack(); - createAudioTrack(); - createLocalStream(); - - if (null != callInviteParams) { - dispatchOnStateDidChange(CALL_STATE_RINGING); - setRemoteDescription(callInviteParams); - } - } - } - }); - - } catch (Exception e) { - // GA issue - // it seems that setView triggers some exception like "setRenderer has already been called" - Log.e(LOG_TAG, "## initCallUI(): VideoRendererGui.setView : Exception Msg =" + e.getMessage(), e); - } - - try { - Log.d(LOG_TAG, "## initCallUI() building UI"); - - mFullScreenRTCView = new MXWebRtcView(mContext); - mFullScreenRTCView.setBackgroundColor(ContextCompat.getColor(mContext, android.R.color.black)); - mCallView.addView(mFullScreenRTCView, - new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)); - mFullScreenRTCView.setVisibility(View.GONE); - - mPipRTCView = new MXWebRtcView(mContext); - mCallView.addView(mPipRTCView, - new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)); - mPipRTCView.setBackgroundColor(ContextCompat.getColor(mContext, android.R.color.transparent)); - mPipRTCView.setVisibility(View.GONE); - - if (null != aLocalVideoPosition) { - updateWebRtcViewLayout(mPipRTCView, aLocalVideoPosition); - Log.d(LOG_TAG, "## initCallUI(): " + aLocalVideoPosition); - } else { - updateWebRtcViewLayout(mPipRTCView, new VideoLayoutConfiguration(5, 5, 25, 25)); - } - } catch (Exception e) { - Log.e(LOG_TAG, "## initCallUI(): Exception Msg =" + e.getMessage(), e); - } - - // reported gy google analytics - // it should never happens - if (null != mCallView) { - mCallView.setVisibility(View.VISIBLE); - } - - } else { - Log.d(LOG_TAG, "## initCallUI(): build audio call"); - - // audio call - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - if (null == mPeerConnectionFactory) { - mPeerConnectionFactory = new PeerConnectionFactory(); - createAudioTrack(); - createLocalStream(); - - if (null != callInviteParams) { - dispatchOnStateDidChange(CALL_STATE_RINGING); - setRemoteDescription(callInviteParams); - } - } - } - }); - } - } - - /** - * The activity is paused. - */ - @Override - public void onPause() { - super.onPause(); - - Log.d(LOG_TAG, "onPause"); - - try { - if (!isCallEnded()) { - Log.d(LOG_TAG, "onPause with active call"); - - // unplugged the camera to avoid loosing the video when the application is suspended - if (!isVideoRecordingMuted()) { - muteVideoRecording(true); - mIsCameraUnplugged = true; - } - } - } catch (Exception e) { - Log.e(LOG_TAG, "onPause failed " + e.getMessage(), e); - } - } - - /** - * The activity is resumed. - */ - @Override - public void onResume() { - super.onResume(); - - Log.d(LOG_TAG, "onResume"); - - try { - if (!isCallEnded()) { - Log.d(LOG_TAG, "onResume with active call"); - - if (mIsCameraUnplugged) { - muteVideoRecording(false); - mIsCameraUnplugged = false; - } - } - } catch (Exception e) { - Log.e(LOG_TAG, "onResume failed " + e.getMessage(), e); - } - } - - /** - * Start an outgoing call. - */ - @Override - public void placeCall(VideoLayoutConfiguration aLocalVideoPosition) { - Log.d(LOG_TAG, "placeCall"); - super.placeCall(aLocalVideoPosition); - - dispatchOnStateDidChange(IMXCall.CALL_STATE_WAIT_LOCAL_MEDIA); - initCallUI(null, aLocalVideoPosition); - } - - /** - * Set the remote description - * - * @param callInviteParams the invitation params - */ - private void setRemoteDescription(final JsonObject callInviteParams) { - Log.d(LOG_TAG, "setRemoteDescription " + callInviteParams); - - SessionDescription aDescription = null; - // extract the description - try { - if (callInviteParams.has("offer")) { - JsonObject answer = callInviteParams.getAsJsonObject("offer"); - String type = answer.get("type").getAsString(); - String sdp = answer.get("sdp").getAsString(); - - if (!TextUtils.isEmpty(type) && !TextUtils.isEmpty(sdp)) { - aDescription = new SessionDescription(SessionDescription.Type.OFFER, sdp); - } - } - - } catch (Exception e) { - Log.e(LOG_TAG, "## setRemoteDescription(): Exception Msg=" + e.getMessage(), e); - } - - mPeerConnection.setRemoteDescription(new SdpObserver() { - @Override - public void onCreateSuccess(SessionDescription sessionDescription) { - Log.d(LOG_TAG, "setRemoteDescription onCreateSuccess"); - } - - @Override - public void onSetSuccess() { - Log.d(LOG_TAG, "setRemoteDescription onSetSuccess"); - mIsIncomingPrepared = true; - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - checkPendingCandidates(); - } - }); - } - - @Override - public void onCreateFailure(String s) { - Log.e(LOG_TAG, "setRemoteDescription onCreateFailure " + s); - dispatchOnCallError(CALL_ERROR_CAMERA_INIT_FAILED); - } - - @Override - public void onSetFailure(String s) { - Log.e(LOG_TAG, "setRemoteDescription onSetFailure " + s); - dispatchOnCallError(CALL_ERROR_CAMERA_INIT_FAILED); - } - }, aDescription); - } - - /** - * Prepare a call reception. - * - * @param aCallInviteParams the invitation Event content - * @param aCallId the call ID - */ - @Override - public void prepareIncomingCall(final JsonObject aCallInviteParams, final String aCallId, final VideoLayoutConfiguration aLocalVideoPosition) { - Log.d(LOG_TAG, "## prepareIncomingCall : call state " + getCallState()); - super.prepareIncomingCall(aCallInviteParams, aCallId, aLocalVideoPosition); - mCallId = aCallId; - - if (CALL_STATE_READY.equals(getCallState())) { - mIsIncoming = true; - - dispatchOnStateDidChange(CALL_STATE_WAIT_LOCAL_MEDIA); - - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - initCallUI(aCallInviteParams, aLocalVideoPosition); - } - }); - } else if (CALL_STATE_CREATED.equals(getCallState())) { - mCallInviteParams = aCallInviteParams; - - // detect call type from the sdp - try { - JsonObject offer = mCallInviteParams.get("offer").getAsJsonObject(); - JsonElement sdp = offer.get("sdp"); - String sdpValue = sdp.getAsString(); - setIsVideo(sdpValue.contains("m=video")); - } catch (Exception e) { - Log.e(LOG_TAG, "## prepareIncomingCall(): Exception Msg=" + e.getMessage(), e); - } - } - } - - /** - * The call has been detected as an incoming one. - * The application launches the dedicated activity and expects to launch the incoming call. - * The local video attendee is displayed in the screen according to the values given in aLocalVideoPosition. - * - * @param aLocalVideoPosition local video position - */ - @Override - public void launchIncomingCall(VideoLayoutConfiguration aLocalVideoPosition) { - Log.d(LOG_TAG, "launchIncomingCall : call state " + getCallState()); - - super.launchIncomingCall(aLocalVideoPosition); - if (CALL_STATE_READY.equals(getCallState())) { - prepareIncomingCall(mCallInviteParams, mCallId, aLocalVideoPosition); - } - } - - /** - * The callee accepts the call. - * - * @param event the event - */ - private void onCallAnswer(final Event event) { - Log.d(LOG_TAG, "onCallAnswer : call state " + getCallState()); - - if (!CALL_STATE_CREATED.equals(getCallState()) && (null != mPeerConnection)) { - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - dispatchOnStateDidChange(IMXCall.CALL_STATE_CONNECTING); - SessionDescription aDescription = null; - - // extract the description - try { - JsonObject eventContent = event.getContentAsJsonObject(); - - if (eventContent.has("answer")) { - JsonObject answer = eventContent.getAsJsonObject("answer"); - String type = answer.get("type").getAsString(); - String sdp = answer.get("sdp").getAsString(); - - if (!TextUtils.isEmpty(type) && !TextUtils.isEmpty(sdp) && type.equals("answer")) { - aDescription = new SessionDescription(SessionDescription.Type.ANSWER, sdp); - } - } - - } catch (Exception e) { - Log.e(LOG_TAG, "onCallAnswer : " + e.getMessage(), e); - } - - mPeerConnection.setRemoteDescription(new SdpObserver() { - @Override - public void onCreateSuccess(SessionDescription sessionDescription) { - Log.d(LOG_TAG, "setRemoteDescription onCreateSuccess"); - } - - @Override - public void onSetSuccess() { - Log.d(LOG_TAG, "setRemoteDescription onSetSuccess"); - } - - @Override - public void onCreateFailure(String s) { - Log.e(LOG_TAG, "setRemoteDescription onCreateFailure " + s); - dispatchOnCallError(CALL_ERROR_CAMERA_INIT_FAILED); - } - - @Override - public void onSetFailure(String s) { - Log.e(LOG_TAG, "setRemoteDescription onSetFailure " + s); - dispatchOnCallError(CALL_ERROR_CAMERA_INIT_FAILED); - } - }, aDescription); - } - }); - } - } - - /** - * The other call member hangs up the call. - * - * @param hangUpReasonId hang up reason - */ - private void onCallHangup(final int hangUpReasonId) { - Log.d(LOG_TAG, "## onCallHangup(): call state=" + getCallState()); - String state = getCallState(); - - if (!CALL_STATE_CREATED.equals(state) && (null != mPeerConnection)) { - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - terminate(hangUpReasonId); - } - }); - } else if (CALL_STATE_WAIT_LOCAL_MEDIA.equals(state) && isVideo()) { - // specific case fixing: a video call hung up by the calling side - // when the callee is still displaying the InComingCallActivity dialog. - // If terminate() was not called, the dialog was never dismissed. - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - terminate(hangUpReasonId); - } - }); - } - } - - /** - * A new Ice candidate is received - * - * @param candidates the channel candidates - */ - private void onNewCandidates(final JsonArray candidates) { - Log.d(LOG_TAG, "## onNewCandidates(): call state " + getCallState() + " with candidates " + candidates); - - if (!CALL_STATE_CREATED.equals(getCallState()) && (null != mPeerConnection)) { - List candidatesList = new ArrayList<>(); - - // convert the JSON to IceCandidate - for (int index = 0; index < candidates.size(); index++) { - JsonObject item = candidates.get(index).getAsJsonObject(); - try { - String candidate = item.get("candidate").getAsString(); - String sdpMid = item.get("sdpMid").getAsString(); - int sdpLineIndex = item.get("sdpMLineIndex").getAsInt(); - - candidatesList.add(new IceCandidate(sdpMid, sdpLineIndex, candidate)); - } catch (Exception e) { - Log.e(LOG_TAG, "## onNewCandidates(): Exception Msg=" + e.getMessage(), e); - } - } - - for (IceCandidate cand : candidatesList) { - Log.d(LOG_TAG, "## onNewCandidates(): addIceCandidate " + cand); - mPeerConnection.addIceCandidate(cand); - } - } - } - - /** - * Add ice candidates - * - * @param candidates ic candidates - */ - private void addCandidates(JsonArray candidates) { - if (mIsIncomingPrepared || !isIncoming()) { - Log.d(LOG_TAG, "addCandidates : ready"); - onNewCandidates(candidates); - } else { - synchronized (LOG_TAG) { - Log.d(LOG_TAG, "addCandidates : pending"); - mPendingCandidates.addAll(candidates); - } - } - } - - /** - * Some Ice candidates could have been received while creating the call view. - * Check if some of them have been defined. - */ - private void checkPendingCandidates() { - Log.d(LOG_TAG, "checkPendingCandidates"); - - synchronized (LOG_TAG) { - onNewCandidates(mPendingCandidates); - mPendingCandidates = new JsonArray(); - } - } - - // events thread - - /** - * Manage the call events. - * - * @param event the call event. - */ - @Override - public void handleCallEvent(Event event) { - super.handleCallEvent(event); - - if (event.isCallEvent()) { - String eventType = event.getType(); - - Log.d(LOG_TAG, "handleCallEvent " + eventType); - - // event from other member - if (!TextUtils.equals(event.getSender(), mSession.getMyUserId())) { - if (Event.EVENT_TYPE_CALL_ANSWER.equals(eventType) && !mIsIncoming) { - onCallAnswer(event); - } else if (Event.EVENT_TYPE_CALL_CANDIDATES.equals(eventType)) { - JsonObject eventContent = event.getContentAsJsonObject(); - - JsonArray candidates = eventContent.getAsJsonArray("candidates"); - addCandidates(candidates); - } else if (Event.EVENT_TYPE_CALL_HANGUP.equals(eventType)) { - onCallHangup(IMXCall.END_CALL_REASON_PEER_HANG_UP); - } - - } else { // event from the current member, but sent from another device - switch (eventType) { - case Event.EVENT_TYPE_CALL_INVITE: - // warn in the UI thread - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - dispatchOnStateDidChange(CALL_STATE_RINGING); - } - }); - break; - - case Event.EVENT_TYPE_CALL_ANSWER: - // call answered from another device - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - onAnsweredElsewhere(); - } - }); - break; - - case Event.EVENT_TYPE_CALL_HANGUP: - // current member answered elsewhere - onCallHangup(IMXCall.END_CALL_REASON_PEER_HANG_UP_ELSEWHERE); - break; - - default: - break; - } // switch end - } - } - } - - // user actions - - /** - * The call is accepted. - */ - @Override - public void answer() { - super.answer(); - Log.d(LOG_TAG, "answer " + getCallState()); - - if (!CALL_STATE_CREATED.equals(getCallState()) && (null != mPeerConnection)) { - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - if (null == mPeerConnection) { - Log.d(LOG_TAG, "answer the connection has been closed"); - return; - } - - dispatchOnStateDidChange(CALL_STATE_CREATE_ANSWER); - - MediaConstraints constraints = new MediaConstraints(); - constraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true")); - constraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveVideo", isVideo() ? "true" : "false")); - - mPeerConnection.createAnswer(new SdpObserver() { - @Override - public void onCreateSuccess(SessionDescription sessionDescription) { - Log.d(LOG_TAG, "createAnswer onCreateSuccess"); - - final SessionDescription sdp = new SessionDescription(sessionDescription.type, sessionDescription.description); - - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - if (mPeerConnection != null) { - // must be done to before sending the invitation message - mPeerConnection.setLocalDescription(new SdpObserver() { - @Override - public void onCreateSuccess(SessionDescription sessionDescription) { - Log.d(LOG_TAG, "setLocalDescription onCreateSuccess"); - } - - @Override - public void onSetSuccess() { - Log.d(LOG_TAG, "setLocalDescription onSetSuccess"); - sendAnswer(sdp); - dispatchOnStateDidChange(IMXCall.CALL_STATE_CONNECTING); - } - - @Override - public void onCreateFailure(String s) { - Log.e(LOG_TAG, "setLocalDescription onCreateFailure " + s); - dispatchOnCallError(CALL_ERROR_CAMERA_INIT_FAILED); - hangup(null); - } - - @Override - public void onSetFailure(String s) { - Log.e(LOG_TAG, "setLocalDescription onSetFailure " + s); - dispatchOnCallError(CALL_ERROR_CAMERA_INIT_FAILED); - hangup(null); - } - }, sdp); - } - } - }); - } - - @Override - public void onSetSuccess() { - Log.d(LOG_TAG, "createAnswer onSetSuccess"); - } - - @Override - public void onCreateFailure(String s) { - Log.e(LOG_TAG, "createAnswer onCreateFailure " + s); - dispatchOnCallError(CALL_ERROR_CAMERA_INIT_FAILED); - hangup(null); - } - - @Override - public void onSetFailure(String s) { - Log.e(LOG_TAG, "createAnswer onSetFailure " + s); - dispatchOnCallError(CALL_ERROR_CAMERA_INIT_FAILED); - hangup(null); - } - }, constraints); - - } - }); - } - - } - - /** - * The call is hung up. - */ - @Override - public void hangup(String reason) { - super.hangup(reason); - - Log.d(LOG_TAG, "## hangup(): reason=" + reason); - - if (!isCallEnded()) { - sendHangup(reason); - terminate(IMXCall.END_CALL_REASON_UNDEFINED); - } - } - - /** - * @return the callstate (must be a CALL_STATE_XX value) - */ - @Override - public String getCallState() { - return mCallState; - } - - /** - * @return the callView - */ - @Override - public View getCallView() { - return mCallView; - } - - /** - * @return the callView visibility - */ - @Override - public int getVisibility() { - if (null != mCallView) { - return mCallView.getVisibility(); - } else { - return View.GONE; - } - } - - /** - * Set the callview visibility - * - * @return true if the operation succeeds - */ - @Override - public boolean setVisibility(int visibility) { - if (null != mCallView) { - mCallView.setVisibility(visibility); - return true; - } - - return false; - } - - /** - * The call has been answered on another device. - * We distinguish the case where an account is active on - * multiple devices and a video call is launched on the account. In this case - * the callee who did not answer must display a "answered elsewhere" message. - */ - @Override - public void onAnsweredElsewhere() { - super.onAnsweredElsewhere(); - - String state = getCallState(); - - Log.d(LOG_TAG, "onAnsweredElsewhere in state " + state); - - if (!isCallEnded() && !mIsAnswered) { - dispatchAnsweredElsewhere(); - terminate(IMXCall.END_CALL_REASON_UNDEFINED); - } - } - - @Override - protected void dispatchOnStateDidChange(String newState) { - Log.d(LOG_TAG, "dispatchOnStateDidChange " + newState); - - mCallState = newState; - - // call timeout management - if (CALL_STATE_CONNECTING.equals(mCallState) || CALL_STATE_CONNECTED.equals(mCallState)) { - if (null != mCallTimeoutTimer) { - mCallTimeoutTimer.cancel(); - mCallTimeoutTimer = null; - } - } - - super.dispatchOnStateDidChange(newState); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/MXWebRtcView.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/MXWebRtcView.java deleted file mode 100644 index 79925e03..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/MXWebRtcView.java +++ /dev/null @@ -1,520 +0,0 @@ -package im.vector.matrix.android.internal.legacy.call; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.graphics.Point; -import android.support.v4.view.ViewCompat; -import android.util.Log; -import android.view.View; -import android.view.ViewGroup; - -import com.oney.WebRTCModule.EglUtils; -import com.oney.WebRTCModule.WebRTCView; - -import org.webrtc.EglBase; -import org.webrtc.MediaStream; -import org.webrtc.RendererCommon; -import org.webrtc.RendererCommon.RendererEvents; -import org.webrtc.RendererCommon.ScalingType; -import org.webrtc.SurfaceViewRenderer; -import org.webrtc.VideoRenderer; -import org.webrtc.VideoTrack; - -import java.lang.reflect.Method; -import java.util.List; - -/** - * Use the older implementation of WebRtcView. - * The latest version a stream URL instead of a stream. - * It implies to have a React context. - */ -public class MXWebRtcView extends ViewGroup { - /** - * The scaling type to be utilized by default. - *

- * The default value is in accord with - * https://www.w3.org/TR/html5/embedded-content-0.html#the-video-element: - *

- * In the absence of style rules to the contrary, video content should be - * rendered inside the element's playback area such that the video content - * is shown centered in the playback area at the largest possible size that - * fits completely within it, with the video content's aspect ratio being - * preserved. Thus, if the aspect ratio of the playback area does not match - * the aspect ratio of the video, the video will be shown letterboxed or - * pillarboxed. Areas of the element's playback area that do not contain the - * video represent nothing. - */ - private static final ScalingType DEFAULT_SCALING_TYPE - = ScalingType.SCALE_ASPECT_FIT; - - /** - * {@link View#isInLayout()} as a Method to be invoked via - * reflection in order to accommodate its lack of availability before API - * level 18. {@link ViewCompat#isInLayout(View)} is the best solution but I - * could not make it available along with - * {@link ViewCompat#isAttachedToWindow(View)} at the time of this writing. - */ - private static final Method IS_IN_LAYOUT; - - private static final String LOG_TAG = MXWebRtcView.class.getSimpleName(); - - static { - // IS_IN_LAYOUT - Method isInLayout = null; - - try { - Method m = MXWebRtcView.class.getMethod("isInLayout"); - - if (boolean.class.isAssignableFrom(m.getReturnType())) { - isInLayout = m; - } - } catch (NoSuchMethodException e) { - // Fall back to the behavior of ViewCompat#isInLayout(View). - } - IS_IN_LAYOUT = isInLayout; - } - - /** - * The height of the last video frame rendered by - * {@link #surfaceViewRenderer}. - */ - private int frameHeight; - - /** - * The rotation (degree) of the last video frame rendered by - * {@link #surfaceViewRenderer}. - */ - private int frameRotation; - - /** - * The width of the last video frame rendered by - * {@link #surfaceViewRenderer}. - */ - private int frameWidth; - - /** - * The {@code Object} which synchronizes the access to the layout-related - * state of this instance such as {@link #frameHeight}, - * {@link #frameRotation}, {@link #frameWidth}, and {@link #scalingType}. - */ - private final Object layoutSyncRoot = new Object(); - - /** - * The indicator which determines whether this {@code WebRTCView} is to - * mirror the video represented by {@link #videoTrack} during its rendering. - */ - private boolean mirror; - - - /** - * The {@code RendererEvents} which listens to rendering events reported by - * {@link #surfaceViewRenderer}. - */ - private final RendererEvents rendererEvents - = new RendererEvents() { - @Override - public void onFirstFrameRendered() { - } - - @Override - public void onFrameResolutionChanged( - int videoWidth, int videoHeight, - int rotation) { - MXWebRtcView.this.onFrameResolutionChanged( - videoWidth, videoHeight, - rotation); - } - }; - - /** - * The {@code Runnable} representation of - * {@link #requestSurfaceViewRendererLayout()}. Explicitly defined in order - * to allow the use of the latter with {@link #post(Runnable)} without - * initializing new instances on every (method) call. - */ - private final Runnable requestSurfaceViewRendererLayoutRunnable - = new Runnable() { - @Override - public void run() { - requestSurfaceViewRendererLayout(); - } - }; - - /** - * The scaling type this {@code WebRTCView} is to apply to the video - * represented by {@link #videoTrack} during its rendering. An expression of - * the CSS property {@code object-fit} in the terms of WebRTC. - */ - private ScalingType scalingType; - - /** - * The {@link View} and {@link VideoRenderer} implementation which - * actually renders {@link #videoTrack} on behalf of this instance. - */ - private final SurfaceViewRenderer surfaceViewRenderer; - - /** - * The {@code VideoRenderer}, if any, which renders {@link #videoTrack} on - * this {@code View}. - */ - private VideoRenderer videoRenderer; - - /** - * The {@code VideoTrack}, if any, rendered by this {@code MXWebRTCView}. - */ - private VideoTrack videoTrack; - - public MXWebRtcView(Context context) { - super(context); - - surfaceViewRenderer = new SurfaceViewRenderer(context); - addView(surfaceViewRenderer); - - setMirror(false); - setScalingType(DEFAULT_SCALING_TYPE); - } - - /** - * Gets the {@code SurfaceViewRenderer} which renders {@link #videoTrack}. - * Explicitly defined and used in order to facilitate switching the instance - * at compile time. For example, reduces the number of modifications - * necessary to switch the implementation from a {@code SurfaceViewRenderer} - * that is a child of a {@code WebRTCView} to {@code WebRTCView} extending - * {@code SurfaceViewRenderer}. - * - * @return The {@code SurfaceViewRenderer} which renders {@code videoTrack}. - */ - private final SurfaceViewRenderer getSurfaceViewRenderer() { - return surfaceViewRenderer; - } - - /** - * If this View has {@link View#isInLayout()}, invokes it and - * returns its return value; otherwise, returns false like - * {@link ViewCompat#isInLayout(View)}. - * - * @return If this View has View#isInLayout(), invokes it - * and returns its return value; otherwise, returns false. - */ - private boolean invokeIsInLayout() { - Method m = IS_IN_LAYOUT; - boolean b = false; - - if (m != null) { - try { - b = (boolean) m.invoke(this); - } catch (Throwable e) { - // Fall back to the behavior of ViewCompat#isInLayout(View). - } - } - return b; - } - - /** - * {@inheritDoc} - */ - @Override - protected void onAttachedToWindow() { - try { - // Generally, OpenGL is only necessary while this View is attached - // to a window so there is no point in having the whole rendering - // infrastructure hooked up while this View is not attached to a - // window. Additionally, a memory leak was solved in a similar way - // on iOS. - tryAddRendererToVideoTrack(); - } finally { - super.onAttachedToWindow(); - } - } - - /** - * {@inheritDoc} - */ - @Override - protected void onDetachedFromWindow() { - try { - // Generally, OpenGL is only necessary while this View is attached - // to a window so there is no point in having the whole rendering - // infrastructure hooked up while this View is not attached to a - // window. Additionally, a memory leak was solved in a similar way - // on iOS. - removeRendererFromVideoTrack(); - } finally { - super.onDetachedFromWindow(); - } - } - - /** - * Callback fired by {@link #surfaceViewRenderer} when the resolution or - * rotation of the frame it renders has changed. - * - * @param videoWidth The new width of the rendered video frame. - * @param videoHeight The new height of the rendered video frame. - * @param rotation The new rotation of the rendered video frame. - */ - private void onFrameResolutionChanged(int videoWidth, - int videoHeight, - int rotation) { - boolean changed = false; - - synchronized (layoutSyncRoot) { - if (frameHeight != videoHeight) { - frameHeight = videoHeight; - changed = true; - } - if (frameRotation != rotation) { - frameRotation = rotation; - changed = true; - } - if (frameWidth != videoWidth) { - frameWidth = videoWidth; - changed = true; - } - } - if (changed) { - // The onFrameResolutionChanged method call executes on the - // surfaceViewRenderer's render Thread. - post(requestSurfaceViewRendererLayoutRunnable); - } - } - - /** - * {@inheritDoc} - */ - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - int height = b - t; - int width = r - l; - - if (height == 0 || width == 0) { - l = t = r = b = 0; - } else { - int frameHeight; - int frameRotation; - int frameWidth; - ScalingType scalingType; - - synchronized (layoutSyncRoot) { - frameHeight = this.frameHeight; - frameRotation = this.frameRotation; - frameWidth = this.frameWidth; - scalingType = this.scalingType; - } - - SurfaceViewRenderer surfaceViewRenderer = getSurfaceViewRenderer(); - - switch (scalingType) { - case SCALE_ASPECT_FILL: - // Fill this ViewGroup with surfaceViewRenderer and the latter - // will take care of filling itself with the video similarly to - // the cover value the CSS property object-fit. - r = width; - l = 0; - b = height; - t = 0; - break; - case SCALE_ASPECT_FIT: - default: - // Lay surfaceViewRenderer out inside this ViewGroup in accord - // with the contain value of the CSS property object-fit. - // SurfaceViewRenderer will fill itself with the video similarly - // to the cover or contain value of the CSS property object-fit - // (which will not matter, eventually). - if (frameHeight == 0 || frameWidth == 0) { - l = t = r = b = 0; - } else { - float frameAspectRatio - = (frameRotation % 180 == 0) - ? frameWidth / (float) frameHeight - : frameHeight / (float) frameWidth; - Point frameDisplaySize - = RendererCommon.getDisplaySize( - scalingType, - frameAspectRatio, - width, height); - - l = (width - frameDisplaySize.x) / 2; - t = (height - frameDisplaySize.y) / 2; - r = l + frameDisplaySize.x; - b = t + frameDisplaySize.y; - } - break; - } - } - surfaceViewRenderer.layout(l, t, r, b); - } - - /** - * Stops rendering {@link #videoTrack} and releases the associated acquired - * resources (if rendering is in progress). - */ - private void removeRendererFromVideoTrack() { - if (videoRenderer != null) { - videoTrack.removeRenderer(videoRenderer); - videoRenderer.dispose(); - videoRenderer = null; - - getSurfaceViewRenderer().release(); - - // Since this WebRTCView is no longer rendering anything, make sure - // surfaceViewRenderer displays nothing as well. - synchronized (layoutSyncRoot) { - frameHeight = 0; - frameRotation = 0; - frameWidth = 0; - } - requestSurfaceViewRendererLayout(); - } - } - - /** - * Request that {@link #surfaceViewRenderer} be laid out (as soon as - * possible) because layout-related state either of this instance or of - * {@code surfaceViewRenderer} has changed. - */ - @SuppressLint("WrongCall") - private void requestSurfaceViewRendererLayout() { - // Google/WebRTC just call requestLayout() on surfaceViewRenderer when - // they change the value of its mirror or surfaceType property. - getSurfaceViewRenderer().requestLayout(); - // The above is not enough though when the video frame's dimensions or - // rotation change. The following will suffice. - if (!invokeIsInLayout()) { - onLayout( - /* changed */ false, - getLeft(), getTop(), getRight(), getBottom()); - } - } - - /** - * Sets the indicator which determines whether this {@code WebRTCView} is to - * mirror the video represented by {@link #videoTrack} during its rendering. - * - * @param mirror If this {@code WebRTCView} is to mirror the video - * represented by {@code videoTrack} during its rendering, {@code true}; - * otherwise, {@code false}. - */ - public void setMirror(boolean mirror) { - if (this.mirror != mirror) { - this.mirror = mirror; - - SurfaceViewRenderer surfaceViewRenderer = getSurfaceViewRenderer(); - - surfaceViewRenderer.setMirror(mirror); - // SurfaceViewRenderer takes the value of its mirror property into - // account upon its layout. - requestSurfaceViewRendererLayout(); - } - } - - private void setScalingType(ScalingType scalingType) { - SurfaceViewRenderer surfaceViewRenderer; - - synchronized (layoutSyncRoot) { - if (this.scalingType == scalingType) { - return; - } - - this.scalingType = scalingType; - - surfaceViewRenderer = getSurfaceViewRenderer(); - surfaceViewRenderer.setScalingType(scalingType); - } - // Both this instance ant its SurfaceViewRenderer take the value of - // their scalingType properties into account upon their layouts. - requestSurfaceViewRendererLayout(); - } - - /** - * Sets the {@code MediaStream} to be rendered by this {@code WebRTCView}. - * The implementation renders the first {@link VideoTrack}, if any, of the - * specified {@code mediaStream}. - * - * @param mediaStream The {@code MediaStream} to be rendered by this - * {@code WebRTCView} or {@code null}. - */ - public void setStream(MediaStream mediaStream) { - VideoTrack videoTrack; - - if (mediaStream == null) { - videoTrack = null; - } else { - List videoTracks = mediaStream.videoTracks; - - videoTrack = videoTracks.isEmpty() ? null : videoTracks.get(0); - } - - setVideoTrack(videoTrack); - } - - /** - * Sets the {@code VideoTrack} to be rendered by this {@code WebRTCView}. - * - * @param videoTrack The {@code VideoTrack} to be rendered by this - * {@code WebRTCView} or {@code null}. - */ - private void setVideoTrack(VideoTrack videoTrack) { - VideoTrack oldValue = this.videoTrack; - - if (oldValue != videoTrack) { - if (oldValue != null) { - removeRendererFromVideoTrack(); - } - - this.videoTrack = videoTrack; - - if (videoTrack != null) { - tryAddRendererToVideoTrack(); - } - } - } - - /** - * Sets the z-order of this {@link WebRTCView} in the stacking space of all - * {@code WebRTCView}s. For more details, refer to the documentation of the - * {@code zOrder} property of the JavaScript counterpart of - * {@code WebRTCView} i.e. {@code RTCView}. - * - * @param zOrder The z-order to set on this {@code WebRTCView}. - */ - public void setZOrder(int zOrder) { - SurfaceViewRenderer surfaceViewRenderer = getSurfaceViewRenderer(); - - switch (zOrder) { - case 0: - surfaceViewRenderer.setZOrderMediaOverlay(false); - break; - case 1: - surfaceViewRenderer.setZOrderMediaOverlay(true); - break; - case 2: - surfaceViewRenderer.setZOrderOnTop(true); - break; - } - } - - /** - * Starts rendering {@link #videoTrack} if rendering is not in progress and - * all preconditions for the start of rendering are met. - */ - private void tryAddRendererToVideoTrack() { - if (videoRenderer == null - && videoTrack != null - && ViewCompat.isAttachedToWindow(this)) { - EglBase.Context sharedContext = EglUtils.getRootEglBaseContext(); - - if (sharedContext == null) { - // If SurfaceViewRenderer#init() is invoked, it will throw a - // RuntimeException which will very likely kill the application. - Log.e(LOG_TAG, "Failed to render a VideoTrack!"); - return; - } - - SurfaceViewRenderer surfaceViewRenderer = getSurfaceViewRenderer(); - surfaceViewRenderer.init(sharedContext, rendererEvents); - - videoRenderer = new VideoRenderer(surfaceViewRenderer); - videoTrack.addRenderer(videoRenderer); - } - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/VideoLayoutConfiguration.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/VideoLayoutConfiguration.java deleted file mode 100644 index 903686da..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/call/VideoLayoutConfiguration.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2015 OpenMarket 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.matrix.android.internal.legacy.call; - -import java.io.Serializable; - -/** - * Defines the video call view layout. - */ -public class VideoLayoutConfiguration implements Serializable { - public final static int INVALID_VALUE = -1; - - @Override - public String toString() { - return "VideoLayoutConfiguration{" + - "mIsPortrait=" + mIsPortrait + - ", X=" + mX + - ", Y=" + mY + - ", Width=" + mWidth + - ", Height=" + mHeight + - '}'; - } - - // parameters of the video of the local user (small video) - /** - * margin left in percentage of the screen resolution for the local user video - **/ - public int mX; - /** - * margin top in percentage of the screen resolution for the local user video - **/ - public int mY; - - /** - * width in percentage of the screen resolution for the local user video - **/ - public int mWidth; - /** - * video height in percentage of the screen resolution for the local user video - **/ - public int mHeight; - - /** - * the area size in which the video in displayed - **/ - public int mDisplayWidth; - public int mDisplayHeight; - - /** - * tells if the display in is a portrait orientation - **/ - public boolean mIsPortrait; - - public VideoLayoutConfiguration(int aX, int aY, int aWidth, int aHeight) { - this(aX, aY, aWidth, aHeight, INVALID_VALUE, INVALID_VALUE); - } - - public VideoLayoutConfiguration(int aX, int aY, int aWidth, int aHeight, int aDisplayWidth, int aDisplayHeight) { - mX = aX; - mY = aY; - mWidth = aWidth; - mHeight = aHeight; - mDisplayWidth = aDisplayWidth; - mDisplayHeight = aDisplayHeight; - } - - public VideoLayoutConfiguration() { - mX = INVALID_VALUE; - mY = INVALID_VALUE; - mWidth = INVALID_VALUE; - mHeight = INVALID_VALUE; - mDisplayWidth = INVALID_VALUE; - mDisplayHeight = INVALID_VALUE; - } -} - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/IncomingRoomKeyRequest.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/IncomingRoomKeyRequest.java deleted file mode 100755 index 31791473..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/IncomingRoomKeyRequest.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.crypto; - -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.RoomKeyRequest; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.RoomKeyRequestBody; - -import im.vector.matrix.android.internal.legacy.util.JsonUtils; - -import java.io.Serializable; - -/** - * IncomingRoomKeyRequest class defines the incoming room keys request. - */ -public class IncomingRoomKeyRequest implements Serializable { - /** - * The user id - */ - public String mUserId; - - /** - * The device id - */ - public String mDeviceId; - - /** - * The request id - */ - public String mRequestId; - - /** - * The request body - */ - public RoomKeyRequestBody mRequestBody; - - /** - * The runnable to call to accept to share the keys - */ - public transient Runnable mShare; - - /** - * The runnable to call to ignore the key share request. - */ - public transient Runnable mIgnore; - - /** - * Constructor - * - * @param event the event - */ - public IncomingRoomKeyRequest(Event event) { - mUserId = event.getSender(); - - RoomKeyRequest roomKeyRequest = JsonUtils.toRoomKeyRequest(event.getContentAsJsonObject()); - mDeviceId = roomKeyRequest.requesting_device_id; - mRequestId = roomKeyRequest.request_id; - mRequestBody = (null != roomKeyRequest.body) ? roomKeyRequest.body : new RoomKeyRequestBody(); - } -} - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/IncomingRoomKeyRequestCancellation.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/IncomingRoomKeyRequestCancellation.java deleted file mode 100755 index 45be295f..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/IncomingRoomKeyRequestCancellation.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.crypto; - -import im.vector.matrix.android.internal.legacy.rest.model.Event; - -/** - * IncomingRoomKeyRequestCancellation describes the incoming room key cancellation. - */ -public class IncomingRoomKeyRequestCancellation extends IncomingRoomKeyRequest { - - public IncomingRoomKeyRequestCancellation(Event event) { - super(event); - mRequestBody = null; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXCrypto.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXCrypto.java deleted file mode 100755 index 4943f7cc..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXCrypto.java +++ /dev/null @@ -1,2775 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.crypto; - -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.text.TextUtils; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.reflect.TypeToken; - -import im.vector.matrix.android.internal.legacy.MXSession; -import im.vector.matrix.android.internal.legacy.crypto.algorithms.IMXDecrypting; -import im.vector.matrix.android.internal.legacy.crypto.algorithms.IMXEncrypting; -import im.vector.matrix.android.internal.legacy.crypto.data.MXDeviceInfo; -import im.vector.matrix.android.internal.legacy.crypto.data.MXEncryptEventContentResult; -import im.vector.matrix.android.internal.legacy.crypto.data.MXKey; -import im.vector.matrix.android.internal.legacy.crypto.data.MXOlmInboundGroupSession2; -import im.vector.matrix.android.internal.legacy.crypto.data.MXOlmSessionResult; -import im.vector.matrix.android.internal.legacy.crypto.data.MXUsersDevicesMap; -import im.vector.matrix.android.internal.legacy.data.Room; -import im.vector.matrix.android.internal.legacy.data.RoomState; -import im.vector.matrix.android.internal.legacy.data.cryptostore.IMXCryptoStore; -import im.vector.matrix.android.internal.legacy.listeners.IMXNetworkEventListener; -import im.vector.matrix.android.internal.legacy.listeners.MXEventListener; -import im.vector.matrix.android.internal.legacy.network.NetworkConnectivityReceiver; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.SimpleApiCallback; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.EventContent; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.rest.model.RoomMember; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.KeysUploadResponse; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.RoomKeyContent; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.RoomKeyRequest; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.RoomKeyRequestBody; -import im.vector.matrix.android.internal.legacy.util.JsonUtils; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.lang.reflect.Constructor; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.CountDownLatch; - -/** - * A `MXCrypto` class instance manages the end-to-end crypto for a MXSession instance. - *

- * Messages posted by the user are automatically redirected to MXCrypto in order to be encrypted - * before sending. - * In the other hand, received events goes through MXCrypto for decrypting. - * MXCrypto maintains all necessary keys and their sharing with other devices required for the crypto. - * Specially, it tracks all room membership changes events in order to do keys updates. - */ -public class MXCrypto { - private static final String LOG_TAG = MXCrypto.class.getSimpleName(); - - // max number of keys to upload at once - // Creating keys can be an expensive operation so we limit the - // number we generate in one go to avoid blocking the application - // for too long. - private static final int ONE_TIME_KEY_GENERATION_MAX_NUMBER = 5; - - // frequency with which to check & upload one-time keys - private static final long ONE_TIME_KEY_UPLOAD_PERIOD = 60 * 1000; // one minute - - // The Matrix session. - private final MXSession mSession; - - // the crypto store - public IMXCryptoStore mCryptoStore; - - // MXEncrypting instance for each room. - private final Map mRoomEncryptors; - - // A map from algorithm to MXDecrypting instance, for each room - private final Map> mRoomDecryptors; - - // Our device keys - private MXDeviceInfo mMyDevice; - - // The libolm wrapper. - private MXOlmDevice mOlmDevice; - - private Map> mLastPublishedOneTimeKeys; - - // the encryption is starting - private boolean mIsStarting; - - // tell if the crypto is started - private boolean mIsStarted; - - // the crypto background threads - private HandlerThread mEncryptingHandlerThread = null; - private Handler mEncryptingHandler = null; - - private HandlerThread mDecryptingHandlerThread = null; - private Handler mDecryptingHandler = null; - - // the UI thread - private Handler mUIHandler = null; - - private NetworkConnectivityReceiver mNetworkConnectivityReceiver; - - private Integer mOneTimeKeyCount; - - private final MXDeviceList mDevicesList; - - private final MXOutgoingRoomKeyRequestManager mOutgoingRoomKeyRequestManager; - - private final IMXNetworkEventListener mNetworkListener = new IMXNetworkEventListener() { - @Override - public void onNetworkConnectionUpdate(boolean isConnected) { - if (isConnected && !isStarted()) { - Log.d(LOG_TAG, "Start MXCrypto because a network connection has been retrieved "); - start(false, null); - } - } - }; - - private final MXEventListener mEventListener = new MXEventListener() { - /* - * Warning, if a method is added here, the corresponding call has to be also added in MxEventDispatcher - */ - - @Override - public void onToDeviceEvent(Event event) { - MXCrypto.this.onToDeviceEvent(event); - } - - @Override - public void onLiveEvent(Event event, RoomState roomState) { - if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE_ENCRYPTION)) { - onCryptoEvent(event); - } else if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_STATE_ROOM_MEMBER)) { - onRoomMembership(event); - } - } - }; - - // initialization callbacks - private final List> mInitializationCallbacks = new ArrayList(); - - // Warn the user if some new devices are detected while encrypting a message. - private boolean mWarnOnUnknownDevices = true; - - // tell if there is a OTK check in progress - private boolean mOneTimeKeyCheckInProgress = false; - - // last OTK check timestamp - private long mLastOneTimeKeyCheck = 0; - - // list of IncomingRoomKeyRequests/IncomingRoomKeyRequestCancellations - // we received in the current sync. - private final List mReceivedRoomKeyRequests = new ArrayList<>(); - private final List mReceivedRoomKeyRequestCancellations = new ArrayList<>(); - - // Set of parameters used to configure/customize the end-to-end crypto. - private MXCryptoConfig mCryptoConfig; - - /** - * Constructor - * - * @param matrixSession the session - * @param cryptoStore the crypto store - * @param cryptoConfig the optional set of parameters used to configure the e2e encryption. - */ - public MXCrypto(MXSession matrixSession, IMXCryptoStore cryptoStore, @Nullable MXCryptoConfig cryptoConfig) { - mSession = matrixSession; - mCryptoStore = cryptoStore; - - if (null != cryptoConfig) { - mCryptoConfig = cryptoConfig; - } else { - // Consider the default configuration value - mCryptoConfig = new MXCryptoConfig(); - } - - mOlmDevice = new MXOlmDevice(mCryptoStore); - mRoomEncryptors = new HashMap<>(); - mRoomDecryptors = new HashMap<>(); - - String deviceId = mSession.getCredentials().getDeviceId(); - // deviceId should always be defined - boolean refreshDevicesList = !TextUtils.isEmpty(deviceId); - - if (TextUtils.isEmpty(deviceId)) { - // use the stored one - deviceId = mCryptoStore.getDeviceId(); - } - - if (TextUtils.isEmpty(deviceId)) { - deviceId = UUID.randomUUID().toString(); - Log.d(LOG_TAG, "Warning: No device id in MXCredentials. An id was created. Think of storing it"); - mCryptoStore.storeDeviceId(deviceId); - } - - mMyDevice = new MXDeviceInfo(deviceId); - mMyDevice.userId = mSession.getMyUserId(); - - mDevicesList = new MXDeviceList(matrixSession, this); - - Map keys = new HashMap<>(); - - if (!TextUtils.isEmpty(mOlmDevice.getDeviceEd25519Key())) { - keys.put("ed25519:" + mSession.getCredentials().getDeviceId(), mOlmDevice.getDeviceEd25519Key()); - } - - if (!TextUtils.isEmpty(mOlmDevice.getDeviceCurve25519Key())) { - keys.put("curve25519:" + mSession.getCredentials().getDeviceId(), mOlmDevice.getDeviceCurve25519Key()); - } - - mMyDevice.keys = keys; - - mMyDevice.algorithms = MXCryptoAlgorithms.sharedAlgorithms().supportedAlgorithms(); - mMyDevice.mVerified = MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED; - - // Add our own deviceinfo to the store - Map endToEndDevicesForUser = mCryptoStore.getUserDevices(mSession.getMyUserId()); - - Map myDevices; - - if (null != endToEndDevicesForUser) { - myDevices = new HashMap<>(endToEndDevicesForUser); - } else { - myDevices = new HashMap<>(); - } - - myDevices.put(mMyDevice.deviceId, mMyDevice); - - mCryptoStore.storeUserDevices(mSession.getMyUserId(), myDevices); - mSession.getDataHandler().setCryptoEventsListener(mEventListener); - - mEncryptingHandlerThread = new HandlerThread("MXCrypto_encrypting_" + mSession.getMyUserId(), Thread.MIN_PRIORITY); - mEncryptingHandlerThread.start(); - - mDecryptingHandlerThread = new HandlerThread("MXCrypto_decrypting_" + mSession.getMyUserId(), Thread.MIN_PRIORITY); - mDecryptingHandlerThread.start(); - - mUIHandler = new Handler(Looper.getMainLooper()); - - if (refreshDevicesList) { - // ensure to have the up-to-date devices list - // got some issues when upgrading from Riot < 0.6.4 - mDevicesList.handleDeviceListsChanges(Arrays.asList(mSession.getMyUserId()), null); - } - - mOutgoingRoomKeyRequestManager = new MXOutgoingRoomKeyRequestManager(mSession, this); - - mReceivedRoomKeyRequests.addAll(mCryptoStore.getPendingIncomingRoomKeyRequests()); - } - - /** - * @return the encrypting thread handler - */ - public Handler getEncryptingThreadHandler() { - // mEncryptingHandlerThread was not yet ready - if (null == mEncryptingHandler) { - mEncryptingHandler = new Handler(mEncryptingHandlerThread.getLooper()); - } - - // fail to get the handler - // might happen if the thread is not yet ready - if (null == mEncryptingHandler) { - return mUIHandler; - } - - return mEncryptingHandler; - } - - /** - * @return the decrypting thread handler - */ - private Handler getDecryptingThreadHandler() { - // mDecryptingHandlerThread was not yet ready - if (null == mDecryptingHandler) { - mDecryptingHandler = new Handler(mDecryptingHandlerThread.getLooper()); - } - - // fail to get the handler - // might happen if the thread is not yet ready - if (null == mDecryptingHandler) { - return mUIHandler; - } - - return mDecryptingHandler; - } - - /** - * @return the UI thread handler - */ - public Handler getUIHandler() { - return mUIHandler; - } - - public void setNetworkConnectivityReceiver(NetworkConnectivityReceiver networkConnectivityReceiver) { - mNetworkConnectivityReceiver = networkConnectivityReceiver; - } - - /** - * @return true if some saved data is corrupted - */ - public boolean isCorrupted() { - return (null != mCryptoStore) && mCryptoStore.isCorrupted(); - } - - /** - * @return true if this instance has been released - */ - public boolean hasBeenReleased() { - return (null == mOlmDevice); - } - - /** - * @return my device info - */ - public MXDeviceInfo getMyDevice() { - return mMyDevice; - } - - /** - * @return the crypto store - */ - public IMXCryptoStore getCryptoStore() { - return mCryptoStore; - } - - /** - * @return the deviceList - */ - public MXDeviceList getDeviceList() { - return mDevicesList; - } - - /** - * Provides the tracking status - * - * @param userId the user id - * @return the tracking status - */ - public int getDeviceTrackingStatus(String userId) { - return mCryptoStore.getDeviceTrackingStatus(userId, MXDeviceList.TRACKING_STATUS_NOT_TRACKED); - } - - /** - * Tell if the MXCrypto is started - * - * @return true if the crypto is started - */ - public boolean isStarted() { - return mIsStarted; - } - - /** - * Tells if the MXCrypto is starting. - * - * @return true if the crypto is starting - */ - public boolean isStarting() { - return mIsStarting; - } - - /** - * Start the crypto module. - * Device keys will be uploaded, then one time keys if there are not enough on the homeserver - * and, then, if this is the first time, this new device will be announced to all other users - * devices. - * - * @param isInitialSync true if it starts from an initial sync - * @param aCallback the asynchronous callback - */ - public void start(final boolean isInitialSync, final ApiCallback aCallback) { - synchronized (mInitializationCallbacks) { - if ((null != aCallback) && (mInitializationCallbacks.indexOf(aCallback) < 0)) { - mInitializationCallbacks.add(aCallback); - } - } - - if (mIsStarting) { - return; - } - - // do not start if there is not network connection - if ((null != mNetworkConnectivityReceiver) && !mNetworkConnectivityReceiver.isConnected()) { - // wait that a valid network connection is retrieved - mNetworkConnectivityReceiver.removeEventListener(mNetworkListener); - mNetworkConnectivityReceiver.addEventListener(mNetworkListener); - return; - } - - mIsStarting = true; - - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - uploadDeviceKeys(new ApiCallback() { - private void onError() { - getUIHandler().postDelayed(new Runnable() { - @Override - public void run() { - if (!isStarted()) { - mIsStarting = false; - start(isInitialSync, null); - } - } - }, 1000); - } - - @Override - public void onSuccess(KeysUploadResponse info) { - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - if (!hasBeenReleased()) { - Log.d(LOG_TAG, "###########################################################"); - Log.d(LOG_TAG, "uploadDeviceKeys done for " + mSession.getMyUserId()); - Log.d(LOG_TAG, " - device id : " + mSession.getCredentials().getDeviceId()); - Log.d(LOG_TAG, " - ed25519 : " + mOlmDevice.getDeviceEd25519Key()); - Log.d(LOG_TAG, " - curve25519 : " + mOlmDevice.getDeviceCurve25519Key()); - Log.d(LOG_TAG, " - oneTimeKeys: " + mLastPublishedOneTimeKeys); // They are - Log.d(LOG_TAG, ""); - - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - maybeUploadOneTimeKeys(new ApiCallback() { - @Override - public void onSuccess(Void info) { - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - if (null != mNetworkConnectivityReceiver) { - mNetworkConnectivityReceiver.removeEventListener(mNetworkListener); - } - - mIsStarting = false; - mIsStarted = true; - - mOutgoingRoomKeyRequestManager.start(); - - synchronized (mInitializationCallbacks) { - for (ApiCallback callback : mInitializationCallbacks) { - final ApiCallback fCallback = callback; - getUIHandler().post(new Runnable() { - @Override - public void run() { - fCallback.onSuccess(null); - } - }); - } - mInitializationCallbacks.clear(); - } - - if (isInitialSync) { - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - // refresh the devices list for each known room members - getDeviceList().invalidateAllDeviceLists(); - mDevicesList.refreshOutdatedDeviceLists(); - } - }); - } else { - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - processReceivedRoomKeyRequests(); - } - }); - } - } - }); - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "## start failed : " + e.getMessage(), e); - onError(); - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "## start failed : " + e.getMessage()); - onError(); - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "## start failed : " + e.getMessage(), e); - onError(); - } - }); - } - }); - } - } - }); - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "## start failed : " + e.getMessage(), e); - onError(); - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "## start failed : " + e.getMessage()); - onError(); - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "## start failed : " + e.getMessage(), e); - onError(); - } - }); - } - }); - } - - /** - * Close the crypto - */ - public void close() { - if (null != mEncryptingHandlerThread) { - mSession.getDataHandler().setCryptoEventsListener(null); - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - if (null != mOlmDevice) { - mOlmDevice.release(); - mOlmDevice = null; - } - - mMyDevice = null; - - mCryptoStore.close(); - mCryptoStore = null; - - if (null != mEncryptingHandlerThread) { - mEncryptingHandlerThread.quit(); - mEncryptingHandlerThread = null; - } - - mOutgoingRoomKeyRequestManager.stop(); - } - }); - - getDecryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - if (null != mDecryptingHandlerThread) { - mDecryptingHandlerThread.quit(); - mDecryptingHandlerThread = null; - } - } - }); - } - } - - /** - * @return the olmdevice instance - */ - public MXOlmDevice getOlmDevice() { - return mOlmDevice; - } - - /** - * A sync response has been received - * - * @param syncResponse the syncResponse - * @param fromToken the start sync token - * @param isCatchingUp true if there is a catch-up in progress. - */ - public void onSyncCompleted(final im.vector.matrix.android.internal.session.sync.model.SyncResponse syncResponse, final String fromToken, final boolean isCatchingUp) { - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - if (null != syncResponse.getDeviceLists()) { - getDeviceList().handleDeviceListsChanges(syncResponse.getDeviceLists().getChanged(), syncResponse.getDeviceLists().getLeft()); - } - - if (null != syncResponse.getDeviceOneTimeKeysCount()) { - int currentCount = (null != syncResponse.getDeviceOneTimeKeysCount().getSignedCurve25519()) ? - syncResponse.getDeviceOneTimeKeysCount().getSignedCurve25519() : 0; - updateOneTimeKeyCount(currentCount); - } - - if (isStarted()) { - // Make sure we process to-device messages before generating new one-time-keys #2782 - mDevicesList.refreshOutdatedDeviceLists(); - } - - if (!isCatchingUp && isStarted()) { - maybeUploadOneTimeKeys(); - - processReceivedRoomKeyRequests(); - } - } - }); - } - - /** - * Get the stored device keys for a user. - * - * @param userId the user to list keys for. - * @param callback the asynchronous callback - */ - public void getUserDevices(final String userId, final ApiCallback> callback) { - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - final List list = getUserDevices(userId); - - if (null != callback) { - getUIHandler().post(new Runnable() { - @Override - public void run() { - callback.onSuccess(list); - } - }); - } - } - }); - } - - /** - * Stores the current one_time_key count which will be handled later (in a call of - * _onSyncCompleted). The count is e.g. coming from a /sync response. - * - * @param currentCount the new count - */ - private void updateOneTimeKeyCount(int currentCount) { - mOneTimeKeyCount = currentCount; - } - - /** - * Find a device by curve25519 identity key - * - * @param userId the owner of the device. - * @param algorithm the encryption algorithm. - * @param senderKey the curve25519 key to match. - * @return the device info. - */ - public MXDeviceInfo deviceWithIdentityKey(final String senderKey, final String userId, final String algorithm) { - if (!hasBeenReleased()) { - if (!TextUtils.equals(algorithm, MXCryptoAlgorithms.MXCRYPTO_ALGORITHM_MEGOLM) - && !TextUtils.equals(algorithm, MXCryptoAlgorithms.MXCRYPTO_ALGORITHM_OLM)) { - // We only deal in olm keys - return null; - } - - if (!TextUtils.isEmpty(userId)) { - final List result = new ArrayList<>(); - final CountDownLatch lock = new CountDownLatch(1); - - getDecryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - List devices = getUserDevices(userId); - - if (null != devices) { - for (MXDeviceInfo device : devices) { - Set keys = device.keys.keySet(); - - for (String keyId : keys) { - if (keyId.startsWith("curve25519:")) { - if (TextUtils.equals(senderKey, device.keys.get(keyId))) { - result.add(device); - } - } - } - } - } - - lock.countDown(); - } - }); - - try { - lock.await(); - } catch (Exception e) { - Log.e(LOG_TAG, "## deviceWithIdentityKey() : failed " + e.getMessage(), e); - } - - return (result.size() > 0) ? result.get(0) : null; - } - } - - // Doesn't match a known device - return null; - } - - /** - * Provides the device information for a device id and an user Id - * - * @param userId the user id - * @param deviceId the device id - * @param callback the asynchronous callback - */ - public void getDeviceInfo(final String userId, final String deviceId, final ApiCallback callback) { - getDecryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - final MXDeviceInfo di; - - if (!TextUtils.isEmpty(userId) && !TextUtils.isEmpty(deviceId)) { - di = mCryptoStore.getUserDevice(deviceId, userId); - } else { - di = null; - } - - if (null != callback) { - getUIHandler().post(new Runnable() { - @Override - public void run() { - callback.onSuccess(di); - } - }); - } - } - }); - } - - /** - * Set the devices as known - * - * @param devices the devices - * @param callback the as - */ - public void setDevicesKnown(final List devices, final ApiCallback callback) { - if (hasBeenReleased()) { - return; - } - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - // build a devices map - Map> devicesIdListByUserId = new HashMap<>(); - - for (MXDeviceInfo di : devices) { - List deviceIdsList = devicesIdListByUserId.get(di.userId); - - if (null == deviceIdsList) { - deviceIdsList = new ArrayList<>(); - devicesIdListByUserId.put(di.userId, deviceIdsList); - } - deviceIdsList.add(di.deviceId); - } - - Set userIds = devicesIdListByUserId.keySet(); - - for (String userId : userIds) { - Map storedDeviceIDs = mCryptoStore.getUserDevices(userId); - - // sanity checks - if (null != storedDeviceIDs) { - boolean isUpdated = false; - List deviceIds = devicesIdListByUserId.get(userId); - - for (String deviceId : deviceIds) { - MXDeviceInfo device = storedDeviceIDs.get(deviceId); - - // assume if the device is either verified or blocked - // it means that the device is known - if ((null != device) && device.isUnknown()) { - device.mVerified = MXDeviceInfo.DEVICE_VERIFICATION_UNVERIFIED; - isUpdated = true; - } - } - - if (isUpdated) { - mCryptoStore.storeUserDevices(userId, storedDeviceIDs); - } - } - } - - if (null != callback) { - getUIHandler().post(new Runnable() { - @Override - public void run() { - callback.onSuccess(null); - } - }); - } - } - }); - } - - /** - * Update the blocked/verified state of the given device. - * - * @param verificationStatus the new verification status - * @param deviceId the unique identifier for the device. - * @param userId the owner of the device - * @param callback the asynchronous callback - */ - public void setDeviceVerification(final int verificationStatus, final String deviceId, final String userId, final ApiCallback callback) { - if (hasBeenReleased()) { - return; - } - - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - MXDeviceInfo device = mCryptoStore.getUserDevice(deviceId, userId); - - // Sanity check - if (null == device) { - Log.e(LOG_TAG, "## setDeviceVerification() : Unknown device " + userId + ":" + deviceId); - if (null != callback) { - getUIHandler().post(new Runnable() { - @Override - public void run() { - callback.onSuccess(null); - } - }); - } - return; - } - - if (device.mVerified != verificationStatus) { - device.mVerified = verificationStatus; - mCryptoStore.storeUserDevice(userId, device); - } - - if (null != callback) { - getUIHandler().post(new Runnable() { - @Override - public void run() { - callback.onSuccess(null); - } - }); - } - } - }); - } - - /** - * Configure a room to use encryption. - * This method must be called in getEncryptingThreadHandler - * - * @param roomId the room id to enable encryption in. - * @param algorithm the encryption config for the room. - * @param inhibitDeviceQuery true to suppress device list query for users in the room (for now) - * @param members list of members to start tracking their devices - * @return true if the operation succeeds. - */ - private boolean setEncryptionInRoom(String roomId, String algorithm, boolean inhibitDeviceQuery, List members) { - if (hasBeenReleased()) { - return false; - } - - // If we already have encryption in this room, we should ignore this event - // (for now at least. Maybe we should alert the user somehow?) - String existingAlgorithm = mCryptoStore.getRoomAlgorithm(roomId); - - if (!TextUtils.isEmpty(existingAlgorithm) && !TextUtils.equals(existingAlgorithm, algorithm)) { - Log.e(LOG_TAG, "## setEncryptionInRoom() : Ignoring m.room.encryption event which requests a change of config in " + roomId); - return false; - } - - Class encryptingClass = MXCryptoAlgorithms.sharedAlgorithms().encryptorClassForAlgorithm(algorithm); - - if (null == encryptingClass) { - Log.e(LOG_TAG, "## setEncryptionInRoom() : Unable to encrypt with " + algorithm); - return false; - } - - mCryptoStore.storeRoomAlgorithm(roomId, algorithm); - - IMXEncrypting alg; - - try { - Constructor ctor = encryptingClass.getConstructors()[0]; - alg = (IMXEncrypting) ctor.newInstance(); - } catch (Exception e) { - Log.e(LOG_TAG, "## setEncryptionInRoom() : fail to load the class", e); - return false; - } - - alg.initWithMatrixSession(mSession, roomId); - - synchronized (mRoomEncryptors) { - mRoomEncryptors.put(roomId, alg); - } - - // if encryption was not previously enabled in this room, we will have been - // ignoring new device events for these users so far. We may well have - // up-to-date lists for some users, for instance if we were sharing other - // e2e rooms with them, so there is room for optimisation here, but for now - // we just invalidate everyone in the room. - if (null == existingAlgorithm) { - Log.d(LOG_TAG, "Enabling encryption in " + roomId + " for the first time; invalidating device lists for all users therein"); - - List userIds = new ArrayList<>(); - - for (RoomMember m : members) { - userIds.add(m.getUserId()); - } - - getDeviceList().startTrackingDeviceList(userIds); - - if (!inhibitDeviceQuery) { - getDeviceList().refreshOutdatedDeviceLists(); - } - } - - return true; - } - - /** - * Tells if a room is encrypted - * - * @param roomId the room id - * @return true if the room is encrypted - */ - public boolean isRoomEncrypted(String roomId) { - boolean res = false; - - if (null != roomId) { - synchronized (mRoomEncryptors) { - res = mRoomEncryptors.containsKey(roomId); - - if (!res) { - Room room = mSession.getDataHandler().getRoom(roomId); - - if (null != room) { - res = room.getState().isEncrypted(); - } - } - } - } - - return res; - } - - /** - * @return the stored device keys for a user. - */ - public List getUserDevices(final String userId) { - Map map = getCryptoStore().getUserDevices(userId); - return (null != map) ? new ArrayList<>(map.values()) : new ArrayList(); - } - - /** - * Try to make sure we have established olm sessions for the given users. - * It must be called in getEncryptingThreadHandler() thread. - * The callback is called in the UI thread. - * - * @param users a list of user ids. - * @param callback the asynchronous callback - */ - public void ensureOlmSessionsForUsers(List users, final ApiCallback> callback) { - Log.d(LOG_TAG, "## ensureOlmSessionsForUsers() : ensureOlmSessionsForUsers " + users); - - Map> devicesByUser = new HashMap<>(); - - for (String userId : users) { - devicesByUser.put(userId, new ArrayList()); - - List devices = getUserDevices(userId); - - for (MXDeviceInfo device : devices) { - String key = device.identityKey(); - - if (TextUtils.equals(key, mOlmDevice.getDeviceCurve25519Key())) { - // Don't bother setting up session to ourself - continue; - } - - if (device.isVerified()) { - // Don't bother setting up sessions with blocked users - continue; - } - - devicesByUser.get(userId).add(device); - } - } - - ensureOlmSessionsForDevices(devicesByUser, callback); - } - - /** - * Try to make sure we have established olm sessions for the given devices. - * It must be called in getCryptoHandler() thread. - * The callback is called in the UI thread. - * - * @param devicesByUser a map from userid to list of devices. - * @param callback the asynchronous callback - */ - public void ensureOlmSessionsForDevices(final Map> devicesByUser, - final ApiCallback> callback) { - List devicesWithoutSession = new ArrayList<>(); - - final MXUsersDevicesMap results = new MXUsersDevicesMap<>(); - - Set userIds = devicesByUser.keySet(); - - for (String userId : userIds) { - List deviceInfos = devicesByUser.get(userId); - - for (MXDeviceInfo deviceInfo : deviceInfos) { - String deviceId = deviceInfo.deviceId; - String key = deviceInfo.identityKey(); - - String sessionId = mOlmDevice.getSessionId(key); - - if (TextUtils.isEmpty(sessionId)) { - devicesWithoutSession.add(deviceInfo); - } - - MXOlmSessionResult olmSessionResult = new MXOlmSessionResult(deviceInfo, sessionId); - results.setObject(olmSessionResult, userId, deviceId); - } - } - - if (devicesWithoutSession.size() == 0) { - if (null != callback) { - getUIHandler().post(new Runnable() { - @Override - public void run() { - callback.onSuccess(results); - } - }); - } - return; - } - - // Prepare the request for claiming one-time keys - MXUsersDevicesMap usersDevicesToClaim = new MXUsersDevicesMap<>(); - - final String oneTimeKeyAlgorithm = MXKey.KEY_SIGNED_CURVE_25519_TYPE; - - for (MXDeviceInfo device : devicesWithoutSession) { - usersDevicesToClaim.setObject(oneTimeKeyAlgorithm, device.userId, device.deviceId); - } - - // TODO: this has a race condition - if we try to send another message - // while we are claiming a key, we will end up claiming two and setting up - // two sessions. - // - // That should eventually resolve itself, but it's poor form. - - Log.d(LOG_TAG, "## claimOneTimeKeysForUsersDevices() : " + usersDevicesToClaim); - - mSession.getCryptoRestClient().claimOneTimeKeysForUsersDevices(usersDevicesToClaim, new ApiCallback>() { - @Override - public void onSuccess(final MXUsersDevicesMap oneTimeKeys) { - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - try { - Log.d(LOG_TAG, "## claimOneTimeKeysForUsersDevices() : keysClaimResponse.oneTimeKeys: " + oneTimeKeys); - - Set userIds = devicesByUser.keySet(); - - for (String userId : userIds) { - List deviceInfos = devicesByUser.get(userId); - - for (MXDeviceInfo deviceInfo : deviceInfos) { - - MXKey oneTimeKey = null; - - List deviceIds = oneTimeKeys.getUserDeviceIds(userId); - - if (null != deviceIds) { - for (String deviceId : deviceIds) { - MXOlmSessionResult olmSessionResult = results.getObject(deviceId, userId); - - if (null != olmSessionResult.mSessionId) { - // We already have a result for this device - continue; - } - - MXKey key = oneTimeKeys.getObject(deviceId, userId); - - if (TextUtils.equals(key.type, oneTimeKeyAlgorithm)) { - oneTimeKey = key; - } - - if (null == oneTimeKey) { - Log.d(LOG_TAG, "## ensureOlmSessionsForDevices() : No one-time keys " + oneTimeKeyAlgorithm - + " for device " + userId + " : " + deviceId); - continue; - } - - // Update the result for this device in results - olmSessionResult.mSessionId = verifyKeyAndStartSession(oneTimeKey, userId, deviceInfo); - } - } - } - } - } catch (Exception e) { - Log.e(LOG_TAG, "## ensureOlmSessionsForDevices() " + e.getMessage(), e); - } - - if (!hasBeenReleased()) { - if (null != callback) { - getUIHandler().post(new Runnable() { - @Override - public void run() { - callback.onSuccess(results); - } - }); - } - } - } - }); - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "## ensureOlmSessionsForUsers(): claimOneTimeKeysForUsersDevices request failed" + e.getMessage(), e); - - if (null != callback) { - callback.onNetworkError(e); - } - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "## ensureOlmSessionsForUsers(): claimOneTimeKeysForUsersDevices request failed" + e.getMessage()); - - if (null != callback) { - callback.onMatrixError(e); - } - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "## ensureOlmSessionsForUsers(): claimOneTimeKeysForUsersDevices request failed" + e.getMessage(), e); - - if (null != callback) { - callback.onUnexpectedError(e); - } - } - }); - } - - private String verifyKeyAndStartSession(MXKey oneTimeKey, String userId, MXDeviceInfo deviceInfo) { - String sessionId = null; - - String deviceId = deviceInfo.deviceId; - String signKeyId = "ed25519:" + deviceId; - String signature = oneTimeKey.signatureForUserId(userId, signKeyId); - - if (!TextUtils.isEmpty(signature) && !TextUtils.isEmpty(deviceInfo.fingerprint())) { - boolean isVerified = false; - String errorMessage = null; - - try { - mOlmDevice.verifySignature(deviceInfo.fingerprint(), oneTimeKey.signalableJSONDictionary(), signature); - isVerified = true; - } catch (Exception e) { - errorMessage = e.getMessage(); - } - - // Check one-time key signature - if (isVerified) { - sessionId = getOlmDevice().createOutboundSession(deviceInfo.identityKey(), oneTimeKey.value); - - if (!TextUtils.isEmpty(sessionId)) { - Log.d(LOG_TAG, "## verifyKeyAndStartSession() : Started new sessionid " + sessionId - + " for device " + deviceInfo + "(theirOneTimeKey: " + oneTimeKey.value + ")"); - } else { - // Possibly a bad key - Log.e(LOG_TAG, "## verifyKeyAndStartSession() : Error starting session with device " + userId + ":" + deviceId); - } - } else { - Log.e(LOG_TAG, "## verifyKeyAndStartSession() : Unable to verify signature on one-time key for device " + userId - + ":" + deviceId + " Error " + errorMessage); - } - } - - return sessionId; - } - - - /** - * Encrypt an event content according to the configuration of the room. - * - * @param eventContent the content of the event. - * @param eventType the type of the event. - * @param room the room the event will be sent. - * @param callback the asynchronous callback - */ - public void encryptEventContent(final JsonElement eventContent, - final String eventType, - final Room room, - final ApiCallback callback) { - // wait that the crypto is really started - if (!isStarted()) { - Log.d(LOG_TAG, "## encryptEventContent() : wait after e2e init"); - - start(false, new ApiCallback() { - @Override - public void onSuccess(Void info) { - encryptEventContent(eventContent, eventType, room, callback); - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "## encryptEventContent() : onNetworkError while waiting to start e2e : " + e.getMessage(), e); - - if (null != callback) { - callback.onNetworkError(e); - } - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "## encryptEventContent() : onMatrixError while waiting to start e2e : " + e.getMessage()); - - if (null != callback) { - callback.onMatrixError(e); - } - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "## encryptEventContent() : onUnexpectedError while waiting to start e2e : " + e.getMessage(), e); - - if (null != callback) { - callback.onUnexpectedError(e); - } - } - }); - - return; - } - - final ApiCallback> apiCallback = new SimpleApiCallback>(callback) { - @Override - public void onSuccess(final List members) { - // just as you are sending a secret message? - final List userdIds = new ArrayList<>(); - - for (RoomMember m : members) { - userdIds.add(m.getUserId()); - } - - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - IMXEncrypting alg; - - synchronized (mRoomEncryptors) { - alg = mRoomEncryptors.get(room.getRoomId()); - } - - if (null == alg) { - String algorithm = room.getState().encryptionAlgorithm(); - - if (null != algorithm) { - if (setEncryptionInRoom(room.getRoomId(), algorithm, false, members)) { - synchronized (mRoomEncryptors) { - alg = mRoomEncryptors.get(room.getRoomId()); - } - } - } - } - - if (null != alg) { - final long t0 = System.currentTimeMillis(); - Log.d(LOG_TAG, "## encryptEventContent() starts"); - - alg.encryptEventContent(eventContent, eventType, userdIds, new ApiCallback() { - @Override - public void onSuccess(final JsonElement encryptedContent) { - Log.d(LOG_TAG, "## encryptEventContent() : succeeds after " + (System.currentTimeMillis() - t0) + " ms"); - - if (null != callback) { - callback.onSuccess(new MXEncryptEventContentResult(encryptedContent, Event.EVENT_TYPE_MESSAGE_ENCRYPTED)); - } - } - - @Override - public void onNetworkError(final Exception e) { - Log.e(LOG_TAG, "## encryptEventContent() : onNetworkError " + e.getMessage(), e); - - if (null != callback) { - callback.onNetworkError(e); - } - } - - @Override - public void onMatrixError(final MatrixError e) { - Log.e(LOG_TAG, "## encryptEventContent() : onMatrixError " + e.getMessage()); - - if (null != callback) { - callback.onMatrixError(e); - } - } - - @Override - public void onUnexpectedError(final Exception e) { - Log.e(LOG_TAG, "## encryptEventContent() : onUnexpectedError " + e.getMessage(), e); - - if (null != callback) { - callback.onUnexpectedError(e); - } - } - }); - } else { - final String algorithm = room.getState().encryptionAlgorithm(); - final String reason = String.format(MXCryptoError.UNABLE_TO_ENCRYPT_REASON, - (null == algorithm) ? MXCryptoError.NO_MORE_ALGORITHM_REASON : algorithm); - Log.e(LOG_TAG, "## encryptEventContent() : " + reason); - - if (null != callback) { - getUIHandler().post(new Runnable() { - @Override - public void run() { - callback.onMatrixError(new MXCryptoError(MXCryptoError.UNABLE_TO_ENCRYPT_ERROR_CODE, - MXCryptoError.UNABLE_TO_ENCRYPT, reason)); - } - }); - } - } - } - }); - } - }; - - // Check whether the event content must be encrypted for the invited members. - boolean encryptForInvitedMembers = mCryptoConfig.mEnableEncryptionForInvitedMembers - && room.shouldEncryptForInvitedMembers(); - - if (encryptForInvitedMembers) { - room.getActiveMembersAsync(apiCallback); - } else { - room.getJoinedMembersAsync(apiCallback); - } - } - - /** - * Decrypt an event - * - * @param event the raw event. - * @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack. - * @return the MXEventDecryptionResult data, or null in case of error - */ - @Nullable - public MXEventDecryptionResult decryptEvent(final Event event, final String timeline) throws MXDecryptionException { - if (null == event) { - Log.e(LOG_TAG, "## decryptEvent : null event"); - return null; - } - - final EventContent eventContent = event.getWireEventContent(); - - if (null == eventContent) { - Log.e(LOG_TAG, "## decryptEvent : empty event content"); - return null; - } - - final List results = new ArrayList<>(); - final CountDownLatch lock = new CountDownLatch(1); - final List exceptions = new ArrayList<>(); - - getDecryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - MXEventDecryptionResult result = null; - IMXDecrypting alg = getRoomDecryptor(event.roomId, eventContent.algorithm); - - if (null == alg) { - String reason = String.format(MXCryptoError.UNABLE_TO_DECRYPT_REASON, event.eventId, eventContent.algorithm); - Log.e(LOG_TAG, "## decryptEvent() : " + reason); - exceptions.add(new MXDecryptionException(new MXCryptoError(MXCryptoError.UNABLE_TO_DECRYPT_ERROR_CODE, - MXCryptoError.UNABLE_TO_DECRYPT, reason))); - } else { - try { - result = alg.decryptEvent(event, timeline); - } catch (MXDecryptionException decryptionException) { - exceptions.add(decryptionException); - } - - if (null != result) { - results.add(result); - } - } - lock.countDown(); - } - }); - - try { - lock.await(); - } catch (Exception e) { - Log.e(LOG_TAG, "## decryptEvent() : failed " + e.getMessage(), e); - } - - if (!exceptions.isEmpty()) { - throw exceptions.get(0); - } - - if (!results.isEmpty()) { - return results.get(0); - } - - return null; - } - - /** - * Reset replay attack data for the given timeline. - * - * @param timelineId the timeline id - */ - public void resetReplayAttackCheckInTimeline(final String timelineId) { - if ((null != timelineId) && (null != getOlmDevice())) { - getDecryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - getOlmDevice().resetReplayAttackCheckInTimeline(timelineId); - } - }); - } - } - - /** - * Encrypt an event payload for a list of devices. - * This method must be called from the getCryptoHandler() thread. - * - * @param payloadFields fields to include in the encrypted payload. - * @param deviceInfos list of device infos to encrypt for. - * @return the content for an m.room.encrypted event. - */ - public Map encryptMessage(Map payloadFields, List deviceInfos) { - if (hasBeenReleased()) { - return new HashMap<>(); - } - - Map deviceInfoParticipantKey = new HashMap<>(); - List participantKeys = new ArrayList<>(); - - for (MXDeviceInfo di : deviceInfos) { - participantKeys.add(di.identityKey()); - deviceInfoParticipantKey.put(di.identityKey(), di); - } - - Map payloadJson = new HashMap<>(payloadFields); - - payloadJson.put("sender", mSession.getMyUserId()); - payloadJson.put("sender_device", mSession.getCredentials().getDeviceId()); - - // Include the Ed25519 key so that the recipient knows what - // device this message came from. - // We don't need to include the curve25519 key since the - // recipient will already know this from the olm headers. - // When combined with the device keys retrieved from the - // homeserver signed by the ed25519 key this proves that - // the curve25519 key and the ed25519 key are owned by - // the same device. - Map keysMap = new HashMap<>(); - keysMap.put("ed25519", mOlmDevice.getDeviceEd25519Key()); - payloadJson.put("keys", keysMap); - - Map ciphertext = new HashMap<>(); - - for (String deviceKey : participantKeys) { - String sessionId = mOlmDevice.getSessionId(deviceKey); - - if (!TextUtils.isEmpty(sessionId)) { - Log.d(LOG_TAG, "Using sessionid " + sessionId + " for device " + deviceKey); - MXDeviceInfo deviceInfo = deviceInfoParticipantKey.get(deviceKey); - - payloadJson.put("recipient", deviceInfo.userId); - - Map recipientsKeysMap = new HashMap<>(); - recipientsKeysMap.put("ed25519", deviceInfo.fingerprint()); - payloadJson.put("recipient_keys", recipientsKeysMap); - - - String payloadString = JsonUtils.convertToUTF8(JsonUtils.canonicalize(JsonUtils.getGson(false).toJsonTree(payloadJson)).toString()); - ciphertext.put(deviceKey, mOlmDevice.encryptMessage(deviceKey, sessionId, payloadString)); - } - } - - Map res = new HashMap<>(); - - res.put("algorithm", MXCryptoAlgorithms.MXCRYPTO_ALGORITHM_OLM); - res.put("sender_key", mOlmDevice.getDeviceCurve25519Key()); - res.put("ciphertext", ciphertext); - - return res; - } - - /** - * Handle the 'toDevice' event - * - * @param event the event - */ - private void onToDeviceEvent(final Event event) { - if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_ROOM_KEY) - || TextUtils.equals(event.getType(), Event.EVENT_TYPE_FORWARDED_ROOM_KEY)) { - getDecryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - onRoomKeyEvent(event); - } - }); - } else if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_ROOM_KEY_REQUEST)) { - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - onRoomKeyRequestEvent(event); - } - }); - } - } - - /** - * Handle a key event. - * This method must be called on getDecryptingThreadHandler() thread. - * - * @param event the key event. - */ - private void onRoomKeyEvent(Event event) { - // sanity check - if (null == event) { - Log.e(LOG_TAG, "## onRoomKeyEvent() : null event"); - return; - } - - RoomKeyContent roomKeyContent = JsonUtils.toRoomKeyContent(event.getContentAsJsonObject()); - - String roomId = roomKeyContent.room_id; - String algorithm = roomKeyContent.algorithm; - - if (TextUtils.isEmpty(roomId) || TextUtils.isEmpty(algorithm)) { - Log.e(LOG_TAG, "## onRoomKeyEvent() : missing fields"); - return; - } - - IMXDecrypting alg = getRoomDecryptor(roomId, algorithm); - - if (null == alg) { - Log.e(LOG_TAG, "## onRoomKeyEvent() : Unable to handle keys for " + algorithm); - return; - } - - alg.onRoomKeyEvent(event); - } - - /** - * Called when we get an m.room_key_request event - * This method must be called on getEncryptingThreadHandler() thread. - * - * @param event the announcement event. - */ - private void onRoomKeyRequestEvent(final Event event) { - RoomKeyRequest roomKeyRequest = JsonUtils.toRoomKeyRequest(event.getContentAsJsonObject()); - - if (null != roomKeyRequest.action) { - switch (roomKeyRequest.action) { - case RoomKeyRequest.ACTION_REQUEST: { - synchronized (mReceivedRoomKeyRequests) { - mReceivedRoomKeyRequests.add(new IncomingRoomKeyRequest(event)); - } - break; - } - - case RoomKeyRequest.ACTION_REQUEST_CANCELLATION: { - synchronized (mReceivedRoomKeyRequestCancellations) { - mReceivedRoomKeyRequestCancellations.add(new IncomingRoomKeyRequestCancellation(event)); - } - break; - } - - default: - Log.e(LOG_TAG, "## onRoomKeyRequestEvent() : unsupported action " + roomKeyRequest.action); - } - } - } - - /** - * Process any m.room_key_request events which were queued up during the - * current sync. - */ - private void processReceivedRoomKeyRequests() { - List receivedRoomKeyRequests = null; - - synchronized (mReceivedRoomKeyRequests) { - if (!mReceivedRoomKeyRequests.isEmpty()) { - receivedRoomKeyRequests = new ArrayList(mReceivedRoomKeyRequests); - mReceivedRoomKeyRequests.clear(); - } - } - - if (null != receivedRoomKeyRequests) { - for (final IncomingRoomKeyRequest request : receivedRoomKeyRequests) { - String userId = request.mUserId; - String deviceId = request.mDeviceId; - RoomKeyRequestBody body = request.mRequestBody; - String roomId = body.room_id; - String alg = body.algorithm; - - Log.d(LOG_TAG, "m.room_key_request from " + userId + ":" + deviceId + " for " + roomId + " / " + body.session_id + " id " + request.mRequestId); - - if (!TextUtils.equals(mSession.getMyUserId(), userId)) { - // TODO: determine if we sent this device the keys already: in - Log.e(LOG_TAG, "## processReceivedRoomKeyRequests() : Ignoring room key request from other user for now"); - return; - } - - // todo: should we queue up requests we don't yet have keys for, - // in case they turn up later? - - // if we don't have a decryptor for this room/alg, we don't have - // the keys for the requested events, and can drop the requests. - - final IMXDecrypting decryptor = getRoomDecryptor(roomId, alg); - - if (null == decryptor) { - Log.e(LOG_TAG, "## processReceivedRoomKeyRequests() : room key request for unknown " + alg + " in room " + roomId); - continue; - } - - if (!decryptor.hasKeysForKeyRequest(request)) { - Log.e(LOG_TAG, "## processReceivedRoomKeyRequests() : room key request for unknown session " + body.session_id); - mCryptoStore.deleteIncomingRoomKeyRequest(request); - continue; - } - - if (TextUtils.equals(deviceId, getMyDevice().deviceId) && TextUtils.equals(mSession.getMyUserId(), userId)) { - Log.d(LOG_TAG, "## processReceivedRoomKeyRequests() : oneself device - ignored"); - mCryptoStore.deleteIncomingRoomKeyRequest(request); - continue; - } - - request.mShare = new Runnable() { - @Override - public void run() { - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - decryptor.shareKeysWithDevice(request); - mCryptoStore.deleteIncomingRoomKeyRequest(request); - } - }); - } - }; - - request.mIgnore = new Runnable() { - @Override - public void run() { - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - mCryptoStore.deleteIncomingRoomKeyRequest(request); - } - }); - } - }; - - // if the device is is verified already, share the keys - MXDeviceInfo device = mCryptoStore.getUserDevice(deviceId, userId); - - if (null != device) { - if (device.isVerified()) { - Log.d(LOG_TAG, "## processReceivedRoomKeyRequests() : device is already verified: sharing keys"); - mCryptoStore.deleteIncomingRoomKeyRequest(request); - request.mShare.run(); - continue; - } - - if (device.isBlocked()) { - Log.d(LOG_TAG, "## processReceivedRoomKeyRequests() : device is blocked -> ignored"); - mCryptoStore.deleteIncomingRoomKeyRequest(request); - continue; - } - } - - mCryptoStore.storeIncomingRoomKeyRequest(request); - onRoomKeyRequest(request); - } - } - - List receivedRoomKeyRequestCancellations = null; - - synchronized (mReceivedRoomKeyRequestCancellations) { - if (!mReceivedRoomKeyRequestCancellations.isEmpty()) { - receivedRoomKeyRequestCancellations = new ArrayList(mReceivedRoomKeyRequestCancellations); - mReceivedRoomKeyRequestCancellations.clear(); - } - } - - if (null != receivedRoomKeyRequestCancellations) { - for (IncomingRoomKeyRequestCancellation request : receivedRoomKeyRequestCancellations) { - Log.d(LOG_TAG, "## ## processReceivedRoomKeyRequests() : m.room_key_request cancellation for " + request.mUserId - + ":" + request.mDeviceId + " id " + request.mRequestId); - - // we should probably only notify the app of cancellations we told it - // about, but we don't currently have a record of that, so we just pass - // everything through. - onRoomKeyRequestCancellation(request); - mCryptoStore.deleteIncomingRoomKeyRequest(request); - } - } - } - - /** - * Handle an m.room.encryption event. - * - * @param event the encryption event. - */ - private void onCryptoEvent(final Event event) { - final EventContent eventContent = event.getWireEventContent(); - - final Room room = mSession.getDataHandler().getRoom(event.roomId); - - // Check whether the event content must be encrypted for the invited members. - boolean encryptForInvitedMembers = mCryptoConfig.mEnableEncryptionForInvitedMembers - && room.shouldEncryptForInvitedMembers(); - - ApiCallback> callback = new ApiCallback>() { - @Override - public void onSuccess(final List info) { - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - setEncryptionInRoom(event.roomId, eventContent.algorithm, true, info); - } - }); - } - - private void onError() { - // Ensure setEncryption in room is done, even if there is a failure to fetch the room members - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - setEncryptionInRoom(event.roomId, eventContent.algorithm, true, room.getState().getLoadedMembers()); - } - }); - } - - @Override - public void onNetworkError(Exception e) { - Log.w(LOG_TAG, "[MXCrypto] onCryptoEvent: Warning: Unable to get all members from the HS. Fallback by using lazy-loaded members", e); - - onError(); - } - - @Override - public void onMatrixError(MatrixError e) { - Log.w(LOG_TAG, "[MXCrypto] onCryptoEvent: Warning: Unable to get all members from the HS. Fallback by using lazy-loaded members"); - - onError(); - } - - @Override - public void onUnexpectedError(Exception e) { - Log.w(LOG_TAG, "[MXCrypto] onCryptoEvent: Warning: Unable to get all members from the HS. Fallback by using lazy-loaded members", e); - - onError(); - } - }; - - if (encryptForInvitedMembers) { - room.getActiveMembersAsync(callback); - } else { - room.getJoinedMembersAsync(callback); - } - } - - /** - * Handle a change in the membership state of a member of a room. - * - * @param event the membership event causing the change - */ - private void onRoomMembership(final Event event) { - final IMXEncrypting alg; - - synchronized (mRoomEncryptors) { - alg = mRoomEncryptors.get(event.roomId); - } - - if (null == alg) { - // No encrypting in this room - return; - } - - final String userId = event.stateKey; - final Room room = mSession.getDataHandler().getRoom(event.roomId); - - RoomMember roomMember = room.getState().getMember(userId); - - if (null != roomMember) { - final String membership = roomMember.membership; - - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - if (TextUtils.equals(membership, RoomMember.MEMBERSHIP_JOIN)) { - // make sure we are tracking the deviceList for this user. - getDeviceList().startTrackingDeviceList(Arrays.asList(userId)); - } else if (TextUtils.equals(membership, RoomMember.MEMBERSHIP_INVITE) - && room.shouldEncryptForInvitedMembers() - && mCryptoConfig.mEnableEncryptionForInvitedMembers) { - // track the deviceList for this invited user. - // Caution: there's a big edge case here in that federated servers do not - // know what other servers are in the room at the time they've been invited. - // They therefore will not send device updates if a user logs in whilst - // their state is invite. - getDeviceList().startTrackingDeviceList(Arrays.asList(userId)); - } - } - }); - } - } - - /** - * Upload my user's device keys. - * This method must called on getEncryptingThreadHandler() thread. - * The callback will called on UI thread. - * - * @param callback the asynchronous callback - */ - private void uploadDeviceKeys(ApiCallback callback) { - // Prepare the device keys data to send - // Sign it - String signature = mOlmDevice.signJSON(mMyDevice.signalableJSONDictionary()); - - Map submap = new HashMap<>(); - submap.put("ed25519:" + mMyDevice.deviceId, signature); - - Map> map = new HashMap<>(); - map.put(mSession.getMyUserId(), submap); - - mMyDevice.signatures = map; - - // For now, we set the device id explicitly, as we may not be using the - // same one as used in login. - mSession.getCryptoRestClient().uploadKeys(mMyDevice.JSONDictionary(), null, mMyDevice.deviceId, callback); - } - - /** - * OTK upload loop - * - * @param keyCount the number of key to generate - * @param keyLimit the limit - * @param callback the asynchronous callback - */ - private void uploadLoop(final int keyCount, final int keyLimit, final ApiCallback callback) { - if (keyLimit <= keyCount) { - // If we don't need to generate any more keys then we are done. - if (null != callback) { - getUIHandler().post(new Runnable() { - @Override - public void run() { - callback.onSuccess(null); - } - }); - } - return; - } - - final int keysThisLoop = Math.min(keyLimit - keyCount, ONE_TIME_KEY_GENERATION_MAX_NUMBER); - - getOlmDevice().generateOneTimeKeys(keysThisLoop); - - uploadOneTimeKeys(new SimpleApiCallback(callback) { - @Override - public void onSuccess(final KeysUploadResponse response) { - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - if (response.hasOneTimeKeyCountsForAlgorithm("signed_curve25519")) { - uploadLoop(response.oneTimeKeyCountsForAlgorithm("signed_curve25519"), keyLimit, callback); - } else { - Log.e(LOG_TAG, "## uploadLoop() : response for uploading keys does not contain one_time_key_counts.signed_curve25519"); - getUIHandler().post(new Runnable() { - @Override - public void run() { - callback.onUnexpectedError( - new Exception("response for uploading keys does not contain one_time_key_counts.signed_curve25519")); - } - }); - } - } - }); - } - }); - } - - /** - * Check if the OTK must be uploaded. - */ - private void maybeUploadOneTimeKeys() { - maybeUploadOneTimeKeys(null); - } - - /** - * Check if the OTK must be uploaded. - * - * @param callback the asynchronous callback - */ - private void maybeUploadOneTimeKeys(final ApiCallback callback) { - if (mOneTimeKeyCheckInProgress) { - getUIHandler().post(new Runnable() { - @Override - public void run() { - if (null != callback) { - callback.onSuccess(null); - } - } - }); - return; - } - - if ((System.currentTimeMillis() - mLastOneTimeKeyCheck) < ONE_TIME_KEY_UPLOAD_PERIOD) { - // we've done a key upload recently. - getUIHandler().post(new Runnable() { - @Override - public void run() { - if (null != callback) { - callback.onSuccess(null); - } - } - }); - return; - } - - mLastOneTimeKeyCheck = System.currentTimeMillis(); - - mOneTimeKeyCheckInProgress = true; - - // We then check how many keys we can store in the Account object. - final long maxOneTimeKeys = getOlmDevice().getMaxNumberOfOneTimeKeys(); - - // Try to keep at most half that number on the server. This leaves the - // rest of the slots free to hold keys that have been claimed from the - // server but we haven't recevied a message for. - // If we run out of slots when generating new keys then olm will - // discard the oldest private keys first. This will eventually clean - // out stale private keys that won't receive a message. - final int keyLimit = (int) Math.floor(maxOneTimeKeys / 2.0); - - if (null != mOneTimeKeyCount) { - uploadOTK(mOneTimeKeyCount, keyLimit, callback); - } else { - // ask the server how many keys we have - mSession.getCryptoRestClient().uploadKeys(null, null, mMyDevice.deviceId, new ApiCallback() { - private void onFailed(String errorMessage) { - if (null != errorMessage) { - Log.e(LOG_TAG, "## uploadKeys() : failed " + errorMessage); - } - mOneTimeKeyCount = null; - mOneTimeKeyCheckInProgress = false; - } - - @Override - public void onSuccess(final KeysUploadResponse keysUploadResponse) { - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - if (!hasBeenReleased()) { - // We need to keep a pool of one time public keys on the server so that - // other devices can start conversations with us. But we can only store - // a finite number of private keys in the olm Account object. - // To complicate things further then can be a delay between a device - // claiming a public one time key from the server and it sending us a - // message. We need to keep the corresponding private key locally until - // we receive the message. - // But that message might never arrive leaving us stuck with duff - // private keys clogging up our local storage. - // So we need some kind of enginering compromise to balance all of - // these factors. - int keyCount = keysUploadResponse.oneTimeKeyCountsForAlgorithm("signed_curve25519"); - uploadOTK(keyCount, keyLimit, callback); - } - } - }); - } - - @Override - public void onNetworkError(final Exception e) { - onFailed(e.getMessage()); - - getUIHandler().post(new Runnable() { - @Override - public void run() { - if (null != callback) { - callback.onNetworkError(e); - } - } - }); - } - - @Override - public void onMatrixError(final MatrixError e) { - onFailed(e.getMessage()); - getUIHandler().post(new Runnable() { - @Override - public void run() { - if (null != callback) { - callback.onMatrixError(e); - } - } - }); - } - - @Override - public void onUnexpectedError(final Exception e) { - onFailed(e.getMessage()); - getUIHandler().post(new Runnable() { - @Override - public void run() { - if (null != callback) { - callback.onUnexpectedError(e); - } - } - }); - } - }); - } - } - - /** - * Upload some the OTKs. - * - * @param keyCount the key count - * @param keyLimit the limit - * @param callback the asynchronous callback - */ - private void uploadOTK(int keyCount, int keyLimit, final ApiCallback callback) { - uploadLoop(keyCount, keyLimit, new ApiCallback() { - private void uploadKeysDone(String errorMessage) { - if (null != errorMessage) { - Log.e(LOG_TAG, "## maybeUploadOneTimeKeys() : failed " + errorMessage); - } - mOneTimeKeyCount = null; - mOneTimeKeyCheckInProgress = false; - } - - @Override - public void onSuccess(Void info) { - Log.d(LOG_TAG, "## maybeUploadOneTimeKeys() : succeeded"); - uploadKeysDone(null); - - getUIHandler().post(new Runnable() { - @Override - public void run() { - if (null != callback) { - callback.onSuccess(null); - } - } - }); - } - - @Override - public void onNetworkError(final Exception e) { - uploadKeysDone(e.getMessage()); - - getUIHandler().post(new Runnable() { - @Override - public void run() { - if (null != callback) { - callback.onNetworkError(e); - } - } - }); - } - - @Override - public void onMatrixError(final MatrixError e) { - uploadKeysDone(e.getMessage()); - - getUIHandler().post(new Runnable() { - @Override - public void run() { - if (null != callback) { - callback.onMatrixError(e); - } - } - }); - } - - @Override - public void onUnexpectedError(final Exception e) { - uploadKeysDone(e.getMessage()); - getUIHandler().post(new Runnable() { - @Override - public void run() { - if (null != callback) { - callback.onUnexpectedError(e); - } - } - }); - } - }); - - } - - /** - * Upload my user's one time keys. - * This method must called on getEncryptingThreadHandler() thread. - * The callback will called on UI thread. - * - * @param callback the asynchronous callback - */ - private void uploadOneTimeKeys(final ApiCallback callback) { - final Map> oneTimeKeys = mOlmDevice.getOneTimeKeys(); - Map oneTimeJson = new HashMap<>(); - - Map curve25519Map = oneTimeKeys.get("curve25519"); - - if (null != curve25519Map) { - for (String key_id : curve25519Map.keySet()) { - Map k = new HashMap<>(); - k.put("key", curve25519Map.get(key_id)); - - // the key is also signed - String signature = mOlmDevice.signJSON(k); - Map submap = new HashMap<>(); - submap.put("ed25519:" + mMyDevice.deviceId, signature); - - Map> map = new HashMap<>(); - map.put(mSession.getMyUserId(), submap); - k.put("signatures", map); - - oneTimeJson.put("signed_curve25519:" + key_id, k); - } - } - - // For now, we set the device id explicitly, as we may not be using the - // same one as used in login. - mSession.getCryptoRestClient().uploadKeys(null, oneTimeJson, mMyDevice.deviceId, new SimpleApiCallback(callback) { - @Override - public void onSuccess(final KeysUploadResponse info) { - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - if (!hasBeenReleased()) { - mLastPublishedOneTimeKeys = oneTimeKeys; - mOlmDevice.markKeysAsPublished(); - - if (null != callback) { - getUIHandler().post(new Runnable() { - @Override - public void run() { - callback.onSuccess(info); - } - }); - } - } - } - }); - } - }); - } - - /** - * Get a decryptor for a given room and algorithm. - * If we already have a decryptor for the given room and algorithm, return - * it. Otherwise try to instantiate it. - * - * @param roomId the room id - * @param algorithm the crypto algorithm - * @return the decryptor - */ - private IMXDecrypting getRoomDecryptor(String roomId, String algorithm) { - // sanity check - if (TextUtils.isEmpty(algorithm)) { - Log.e(LOG_TAG, "## getRoomDecryptor() : null algorithm"); - return null; - } - - if (null == mRoomDecryptors) { - Log.e(LOG_TAG, "## getRoomDecryptor() : null mRoomDecryptors"); - return null; - } - - IMXDecrypting alg = null; - - if (!TextUtils.isEmpty(roomId)) { - synchronized (mRoomDecryptors) { - if (!mRoomDecryptors.containsKey(roomId)) { - mRoomDecryptors.put(roomId, new HashMap()); - } - - alg = mRoomDecryptors.get(roomId).get(algorithm); - } - - if (null != alg) { - return alg; - } - } - - Class decryptingClass = MXCryptoAlgorithms.sharedAlgorithms().decryptorClassForAlgorithm(algorithm); - - if (null != decryptingClass) { - try { - Constructor ctor = decryptingClass.getConstructors()[0]; - alg = (IMXDecrypting) ctor.newInstance(); - - if (null != alg) { - alg.initWithMatrixSession(mSession); - - if (!TextUtils.isEmpty(roomId)) { - synchronized (mRoomDecryptors) { - mRoomDecryptors.get(roomId).put(algorithm, alg); - } - } - } - } catch (Exception e) { - Log.e(LOG_TAG, "## getRoomDecryptor() : fail to load the class", e); - return null; - } - } - - return alg; - } - - /** - * Export the crypto keys - * - * @param password the password - * @param callback the exported keys - */ - public void exportRoomKeys(final String password, final ApiCallback callback) { - exportRoomKeys(password, MXMegolmExportEncryption.DEFAULT_ITERATION_COUNT, callback); - } - - /** - * Export the crypto keys - * - * @param password the password - * @param anIterationCount the encryption iteration count (0 means no encryption) - * @param callback the exported keys - */ - public void exportRoomKeys(final String password, int anIterationCount, final ApiCallback callback) { - final int iterationCount = Math.max(0, anIterationCount); - - getDecryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - if (null == mCryptoStore) { - getUIHandler().post(new Runnable() { - @Override - public void run() { - callback.onSuccess(new byte[0]); - } - }); - return; - } - - List> exportedSessions = new ArrayList<>(); - - List inboundGroupSessions = mCryptoStore.getInboundGroupSessions(); - - for (MXOlmInboundGroupSession2 session : inboundGroupSessions) { - Map map = session.exportKeys(); - - if (null != map) { - exportedSessions.add(map); - } - } - - final byte[] encryptedRoomKeys; - - try { - encryptedRoomKeys = MXMegolmExportEncryption - .encryptMegolmKeyFile(JsonUtils.getGson(false).toJsonTree(exportedSessions).toString(), password, iterationCount); - } catch (Exception e) { - callback.onUnexpectedError(e); - return; - } - - getUIHandler().post(new Runnable() { - @Override - public void run() { - callback.onSuccess(encryptedRoomKeys); - } - }); - } - }); - } - - /** - * Import the room keys - * - * @param roomKeysAsArray the room keys as array. - * @param password the password - * @param callback the asynchronous callback. - */ - public void importRoomKeys(final byte[] roomKeysAsArray, final String password, final ApiCallback callback) { - getDecryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - long t0 = System.currentTimeMillis(); - String roomKeys; - - try { - roomKeys = MXMegolmExportEncryption.decryptMegolmKeyFile(roomKeysAsArray, password); - } catch (final Exception e) { - getUIHandler().post(new Runnable() { - @Override - public void run() { - callback.onUnexpectedError(e); - } - }); - return; - } - - List> importedSessions; - - long t1 = System.currentTimeMillis(); - - Log.d(LOG_TAG, "## importRoomKeys starts"); - - try { - importedSessions = JsonUtils.getGson(false).fromJson(roomKeys, new TypeToken>>() { - }.getType()); - } catch (final Exception e) { - Log.e(LOG_TAG, "## importRoomKeys failed " + e.getMessage(), e); - getUIHandler().post(new Runnable() { - @Override - public void run() { - callback.onUnexpectedError(e); - } - }); - return; - } - - long t2 = System.currentTimeMillis(); - - Log.d(LOG_TAG, "## importRoomKeys retrieve " + importedSessions.size() + "sessions in " + (t1 - t0) + " ms"); - - for (int index = 0; index < importedSessions.size(); index++) { - Map map = importedSessions.get(index); - - MXOlmInboundGroupSession2 session = mOlmDevice.importInboundGroupSession(map); - - if ((null != session) && mRoomDecryptors.containsKey(session.mRoomId)) { - IMXDecrypting decrypting = mRoomDecryptors.get(session.mRoomId).get(map.get("algorithm")); - - if (null != decrypting) { - try { - String sessionId = session.mSession.sessionIdentifier(); - Log.d(LOG_TAG, "## importRoomKeys retrieve mSenderKey " + session.mSenderKey + " sessionId " + sessionId); - - decrypting.onNewSession(session.mSenderKey, sessionId); - } catch (Exception e) { - Log.e(LOG_TAG, "## importRoomKeys() : onNewSession failed " + e.getMessage(), e); - } - } - } - } - - long t3 = System.currentTimeMillis(); - - Log.d(LOG_TAG, "## importRoomKeys : done in " + (t3 - t0) + " ms (" + importedSessions.size() + " sessions)"); - Log.d(LOG_TAG, "## importRoomKeys : decryptMegolmKeyFile done in " + (t1 - t0) + " ms"); - Log.d(LOG_TAG, "## importRoomKeys : JSON parsing " + (t2 - t1) + " ms"); - Log.d(LOG_TAG, "## importRoomKeys : sessions import " + (t3 - t2) + " ms"); - - getUIHandler().post(new Runnable() { - @Override - public void run() { - callback.onSuccess(null); - } - }); - } - }); - } - - /** - * Tells if the encryption must fail if some unknown devices are detected. - * - * @return true to warn when some unknown devices are detected. - */ - public boolean warnOnUnknownDevices() { - return mWarnOnUnknownDevices; - } - - /** - * Update the warn status when some unknown devices are detected. - * - * @param warn true to warn when some unknown devices are detected. - */ - public void setWarnOnUnknownDevices(boolean warn) { - mWarnOnUnknownDevices = warn; - } - - /** - * Provides the list of unknown devices - * - * @param devicesInRoom the devices map - * @return the unknown devices map - */ - public static MXUsersDevicesMap getUnknownDevices(MXUsersDevicesMap devicesInRoom) { - MXUsersDevicesMap unknownDevices = new MXUsersDevicesMap<>(); - - List userIds = devicesInRoom.getUserIds(); - for (String userId : userIds) { - List deviceIds = devicesInRoom.getUserDeviceIds(userId); - for (String deviceId : deviceIds) { - MXDeviceInfo deviceInfo = devicesInRoom.getObject(deviceId, userId); - - if (deviceInfo.isUnknown()) { - unknownDevices.setObject(deviceInfo, userId, deviceId); - } - } - } - - return unknownDevices; - } - - /** - * Check if the user ids list have some unknown devices. - * A success means there is no unknown devices. - * If there are some unknown devices, a MXCryptoError.UNKNOWN_DEVICES_CODE exception is triggered. - * - * @param userIds the user ids list - * @param callback the asynchronous callback. - */ - public void checkUnknownDevices(List userIds, final ApiCallback callback) { - // force the refresh to ensure that the devices list is up-to-date - mDevicesList.downloadKeys(userIds, true, new SimpleApiCallback>(callback) { - @Override - public void onSuccess(MXUsersDevicesMap devicesMap) { - MXUsersDevicesMap unknownDevices = MXCrypto.getUnknownDevices(devicesMap); - - if (unknownDevices.getMap().size() == 0) { - callback.onSuccess(null); - } else { - // trigger an an unknown devices exception - callback.onMatrixError(new MXCryptoError(MXCryptoError.UNKNOWN_DEVICES_CODE, - MXCryptoError.UNABLE_TO_ENCRYPT, MXCryptoError.UNKNOWN_DEVICES_REASON, unknownDevices)); - } - } - }); - } - - /** - * Set the global override for whether the client should ever send encrypted - * messages to unverified devices. - * If false, it can still be overridden per-room. - * If true, it overrides the per-room settings. - * - * @param block true to unilaterally blacklist all - * @param callback the asynchronous callback. - */ - public void setGlobalBlacklistUnverifiedDevices(final boolean block, final ApiCallback callback) { - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - mCryptoStore.setGlobalBlacklistUnverifiedDevices(block); - getUIHandler().post(new Runnable() { - @Override - public void run() { - if (null != callback) { - callback.onSuccess(null); - } - } - }); - } - }); - } - - /** - * Tells whether the client should ever send encrypted messages to unverified devices. - * The default value is false. - * This function must be called in the getEncryptingThreadHandler() thread. - * - * @return true to unilaterally blacklist all unverified devices. - */ - public boolean getGlobalBlacklistUnverifiedDevices() { - return mCryptoStore.getGlobalBlacklistUnverifiedDevices(); - } - - /** - * Tells whether the client should ever send encrypted messages to unverified devices. - * The default value is false. - * messages to unverified devices. - * - * @param callback the asynchronous callback - */ - public void getGlobalBlacklistUnverifiedDevices(final ApiCallback callback) { - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - if (null != callback) { - final boolean status = getGlobalBlacklistUnverifiedDevices(); - - getUIHandler().post(new Runnable() { - @Override - public void run() { - callback.onSuccess(status); - } - }); - } - } - }); - } - - /** - * Tells whether the client should encrypt messages only for the verified devices - * in this room. - * The default value is false. - * This function must be called in the getEncryptingThreadHandler() thread. - * - * @param roomId the room id - * @return true if the client should encrypt messages only for the verified devices. - */ - public boolean isRoomBlacklistUnverifiedDevices(String roomId) { - if (null != roomId) { - return mCryptoStore.getRoomsListBlacklistUnverifiedDevices().contains(roomId); - } else { - return false; - } - } - - /** - * Tells whether the client should encrypt messages only for the verified devices - * in this room. - * The default value is false. - * This function must be called in the getEncryptingThreadHandler() thread. - * - * @param roomId the room id - * @param callback the asynchronous callback - */ - public void isRoomBlacklistUnverifiedDevices(final String roomId, final ApiCallback callback) { - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - final boolean status = isRoomBlacklistUnverifiedDevices(roomId); - - getUIHandler().post(new Runnable() { - @Override - public void run() { - if (null != callback) { - callback.onSuccess(status); - } - } - }); - } - }); - } - - /** - * Manages the room black-listing for unverified devices. - * - * @param roomId the room id - * @param add true to add the room id to the list, false to remove it. - * @param callback the asynchronous callback - */ - private void setRoomBlacklistUnverifiedDevices(final String roomId, final boolean add, final ApiCallback callback) { - final Room room = mSession.getDataHandler().getRoom(roomId); - - // sanity check - if (null == room) { - getUIHandler().post(new Runnable() { - @Override - public void run() { - callback.onSuccess(null); - } - }); - - return; - } - - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - List roomIds = mCryptoStore.getRoomsListBlacklistUnverifiedDevices(); - - if (add) { - if (!roomIds.contains(roomId)) { - roomIds.add(roomId); - } - } else { - roomIds.remove(roomId); - } - - mCryptoStore.setRoomsListBlacklistUnverifiedDevices(roomIds); - - getUIHandler().post(new Runnable() { - @Override - public void run() { - if (null != callback) { - callback.onSuccess(null); - } - } - }); - } - }); - } - - - /** - * Add this room to the ones which don't encrypt messages to unverified devices. - * - * @param roomId the room id - * @param callback the asynchronous callback - */ - public void setRoomBlacklistUnverifiedDevices(final String roomId, final ApiCallback callback) { - setRoomBlacklistUnverifiedDevices(roomId, true, callback); - } - - /** - * Remove this room to the ones which don't encrypt messages to unverified devices. - * - * @param roomId the room id - * @param callback the asynchronous callback - */ - public void setRoomUnblacklistUnverifiedDevices(final String roomId, final ApiCallback callback) { - setRoomBlacklistUnverifiedDevices(roomId, false, callback); - } - - /** - * Send a request for some room keys, if we have not already done so. - * - * @param requestBody requestBody - * @param recipients recipients - */ - public void requestRoomKey(final Map requestBody, final List> recipients) { - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - mOutgoingRoomKeyRequestManager.sendRoomKeyRequest(requestBody, recipients); - } - }); - } - - /** - * Cancel any earlier room key request - * - * @param requestBody requestBody - */ - public void cancelRoomKeyRequest(final Map requestBody) { - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - mOutgoingRoomKeyRequestManager.cancelRoomKeyRequest(requestBody); - } - }); - } - - /** - * Re request the encryption keys required to decrypt an event. - * - * @param event the event to decrypt again. - */ - public void reRequestRoomKeyForEvent(@NonNull final Event event) { - if (event.getWireContent().isJsonObject()) { - JsonObject wireContent = event.getWireContent().getAsJsonObject(); - - final String algorithm = wireContent.get("algorithm").getAsString(); - final String sender_key = wireContent.get("sender_key").getAsString(); - final String session_id = wireContent.get("session_id").getAsString(); - - getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - Map requestBody = new HashMap<>(); - requestBody.put("room_id", event.roomId); - requestBody.put("algorithm", algorithm); - requestBody.put("sender_key", sender_key); - requestBody.put("session_id", session_id); - - mOutgoingRoomKeyRequestManager.resendRoomKeyRequest(requestBody); - } - }); - } - } - - /** - * Room keys events listener - */ - public interface IRoomKeysRequestListener { - /** - * An room key request has been received. - * - * @param request the request - */ - void onRoomKeyRequest(IncomingRoomKeyRequest request); - - /** - * A room key request cancellation has been received. - * - * @param request the cancellation request - */ - void onRoomKeyRequestCancellation(IncomingRoomKeyRequestCancellation request); - } - - // the listeners - public final Set mRoomKeysRequestListeners = new HashSet<>(); - - /** - * Add a IRoomKeysRequestListener listener. - * - * @param listener listener - */ - public void addRoomKeysRequestListener(IRoomKeysRequestListener listener) { - synchronized (mRoomKeysRequestListeners) { - mRoomKeysRequestListeners.add(listener); - } - } - - /** - * Add a IRoomKeysRequestListener listener. - * - * @param listener listener - */ - public void removeRoomKeysRequestListener(IRoomKeysRequestListener listener) { - synchronized (mRoomKeysRequestListeners) { - mRoomKeysRequestListeners.remove(listener); - } - } - - /** - * Dispatch onRoomKeyRequest - * - * @param request the request - */ - private void onRoomKeyRequest(IncomingRoomKeyRequest request) { - synchronized (mRoomKeysRequestListeners) { - for (IRoomKeysRequestListener listener : mRoomKeysRequestListeners) { - try { - listener.onRoomKeyRequest(request); - } catch (Exception e) { - Log.e(LOG_TAG, "## onRoomKeyRequest() failed " + e.getMessage(), e); - } - } - } - } - - - /** - * A room key request cancellation has been received. - * - * @param request the cancellation request - */ - private void onRoomKeyRequestCancellation(IncomingRoomKeyRequestCancellation request) { - synchronized (mRoomKeysRequestListeners) { - for (IRoomKeysRequestListener listener : mRoomKeysRequestListeners) { - try { - listener.onRoomKeyRequestCancellation(request); - } catch (Exception e) { - Log.e(LOG_TAG, "## onRoomKeyRequestCancellation() failed " + e.getMessage(), e); - } - } - } - } -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXCryptoAlgorithms.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXCryptoAlgorithms.java deleted file mode 100755 index 8a4c2199..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXCryptoAlgorithms.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.crypto; - -import android.text.TextUtils; - -import im.vector.matrix.android.internal.legacy.crypto.algorithms.IMXDecrypting; -import im.vector.matrix.android.internal.legacy.crypto.algorithms.IMXEncrypting; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class MXCryptoAlgorithms { - - private static final String LOG_TAG = MXCryptoAlgorithms.class.getSimpleName(); - - /** - * Matrix algorithm tag for olm. - */ - public static final String MXCRYPTO_ALGORITHM_OLM = "m.olm.v1.curve25519-aes-sha2"; - - /** - * Matrix algorithm tag for megolm. - */ - public static final String MXCRYPTO_ALGORITHM_MEGOLM = "m.megolm.v1.aes-sha2"; - - // encryptors map - private final Map> mEncryptors; - - // decryptors map - private final Map> mDecryptors; - - // shared instance - private static MXCryptoAlgorithms mSharedInstance = null; - - /** - * @return the shared instance - */ - public static MXCryptoAlgorithms sharedAlgorithms() { - if (null == mSharedInstance) { - mSharedInstance = new MXCryptoAlgorithms(); - } - - return mSharedInstance; - } - - /** - * Constructor - */ - private MXCryptoAlgorithms() { - // encryptos - mEncryptors = new HashMap<>(); - try { - mEncryptors.put(MXCRYPTO_ALGORITHM_MEGOLM, - (Class) Class.forName("org.matrix.androidsdk.crypto.algorithms.megolm.MXMegolmEncryption")); - } catch (Exception e) { - Log.e(LOG_TAG, "## MXCryptoAlgorithms() : fails to add MXCRYPTO_ALGORITHM_MEGOLM " + e.getMessage(), e); - } - - try { - mEncryptors.put(MXCRYPTO_ALGORITHM_OLM, - (Class) Class.forName("org.matrix.androidsdk.crypto.algorithms.olm.MXOlmEncryption")); - } catch (Exception e) { - Log.e(LOG_TAG, "## MXCryptoAlgorithms() : fails to add MXCRYPTO_ALGORITHM_OLM " + e.getMessage(), e); - } - - mDecryptors = new HashMap<>(); - try { - mDecryptors.put(MXCRYPTO_ALGORITHM_MEGOLM, - (Class) Class.forName("org.matrix.androidsdk.crypto.algorithms.megolm.MXMegolmDecryption")); - } catch (Exception e) { - Log.e(LOG_TAG, "## MXCryptoAlgorithms() : fails to add MXCRYPTO_ALGORITHM_MEGOLM " + e.getMessage(), e); - } - - try { - mDecryptors.put(MXCRYPTO_ALGORITHM_OLM, - (Class) Class.forName("org.matrix.androidsdk.crypto.algorithms.olm.MXOlmDecryption")); - } catch (Exception e) { - Log.e(LOG_TAG, "## MXCryptoAlgorithms() : fails to add MXCRYPTO_ALGORITHM_OLM " + e.getMessage(), e); - } - } - - /** - * Get the class implementing encryption for the provided algorithm. - * - * @param algorithm the algorithm tag. - * @return A class implementing 'IMXEncrypting'. - */ - public Class encryptorClassForAlgorithm(String algorithm) { - if (!TextUtils.isEmpty(algorithm)) { - return mEncryptors.get(algorithm); - } else { - return null; - } - } - - /** - * Get the class implementing decryption for the provided algorithm. - * - * @param algorithm the algorithm tag. - * @return A class implementing 'IMXDecrypting'. - */ - - public Class decryptorClassForAlgorithm(String algorithm) { - if (!TextUtils.isEmpty(algorithm)) { - return mDecryptors.get(algorithm); - } else { - return null; - } - } - - /** - * @return The list of registered algorithms. - */ - public List supportedAlgorithms() { - return new ArrayList<>(mEncryptors.keySet()); - } -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXCryptoConfig.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXCryptoConfig.java deleted file mode 100644 index f1ae3f50..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXCryptoConfig.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.crypto; - -/** - * Class to define the parameters used to customize or configure the end-to-end crypto. - */ -public class MXCryptoConfig { - // Tell whether the encryption of the event content is enabled for the invited members. - // By default, we encrypt messages only for the joined members. - // The encryption for the invited members will be blocked if the history visibility is "joined". - public boolean mEnableEncryptionForInvitedMembers = false; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXCryptoError.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXCryptoError.java deleted file mode 100644 index 9c98d4e2..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXCryptoError.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.crypto; - -import android.text.TextUtils; - -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; - -/** - * Represents a standard error response. - */ -public class MXCryptoError extends MatrixError { - - /** - * Error codes - */ - public static final String ENCRYPTING_NOT_ENABLED_ERROR_CODE = "ENCRYPTING_NOT_ENABLED"; - public static final String UNABLE_TO_ENCRYPT_ERROR_CODE = "UNABLE_TO_ENCRYPT"; - public static final String UNABLE_TO_DECRYPT_ERROR_CODE = "UNABLE_TO_DECRYPT"; - public static final String UNKNOWN_INBOUND_SESSION_ID_ERROR_CODE = "UNKNOWN_INBOUND_SESSION_ID"; - public static final String INBOUND_SESSION_MISMATCH_ROOM_ID_ERROR_CODE = "INBOUND_SESSION_MISMATCH_ROOM_ID"; - public static final String MISSING_FIELDS_ERROR_CODE = "MISSING_FIELDS"; - public static final String MISSING_CIPHER_TEXT_ERROR_CODE = "MISSING_CIPHER_TEXT"; - public static final String NOT_INCLUDE_IN_RECIPIENTS_ERROR_CODE = "NOT_INCLUDE_IN_RECIPIENTS"; - public static final String BAD_RECIPIENT_ERROR_CODE = "BAD_RECIPIENT"; - public static final String BAD_RECIPIENT_KEY_ERROR_CODE = "BAD_RECIPIENT_KEY"; - public static final String FORWARDED_MESSAGE_ERROR_CODE = "FORWARDED_MESSAGE"; - public static final String BAD_ROOM_ERROR_CODE = "BAD_ROOM"; - public static final String BAD_ENCRYPTED_MESSAGE_ERROR_CODE = "BAD_ENCRYPTED_MESSAGE"; - public static final String DUPLICATED_MESSAGE_INDEX_ERROR_CODE = "DUPLICATED_MESSAGE_INDEX"; - public static final String MISSING_PROPERTY_ERROR_CODE = "MISSING_PROPERTY"; - public static final String OLM_ERROR_CODE = "OLM_ERROR_CODE"; - public static final String UNKNOWN_DEVICES_CODE = "UNKNOWN_DEVICES_CODE"; - - /** - * short error reasons - */ - public static final String UNABLE_TO_DECRYPT = "Unable to decrypt"; - public static final String UNABLE_TO_ENCRYPT = "Unable to encrypt"; - - /** - * Detailed error reasons - */ - public static final String ENCRYPTING_NOT_ENABLED_REASON = "Encryption not enabled"; - public static final String UNABLE_TO_ENCRYPT_REASON = "Unable to encrypt %s"; - public static final String UNABLE_TO_DECRYPT_REASON = "Unable to decrypt %1$s. Algorithm: %2$s"; - public static final String OLM_REASON = "OLM error: %1$s"; - public static final String DETAILLED_OLM_REASON = "Unable to decrypt %1$s. OLM error: %2$s"; - public static final String UNKNOWN_INBOUND_SESSION_ID_REASON = "Unknown inbound session id"; - public static final String INBOUND_SESSION_MISMATCH_ROOM_ID_REASON = "Mismatched room_id for inbound group session (expected %1$s, was %2$s)"; - public static final String MISSING_FIELDS_REASON = "Missing fields in input"; - public static final String MISSING_CIPHER_TEXT_REASON = "Missing ciphertext"; - public static final String NOT_INCLUDED_IN_RECIPIENT_REASON = "Not included in recipients"; - public static final String BAD_RECIPIENT_REASON = "Message was intended for %1$s"; - public static final String BAD_RECIPIENT_KEY_REASON = "Message not intended for this device"; - public static final String FORWARDED_MESSAGE_REASON = "Message forwarded from %1$s"; - public static final String BAD_ROOM_REASON = "Message intended for room %1$s"; - public static final String BAD_ENCRYPTED_MESSAGE_REASON = "Bad Encrypted Message"; - public static final String DUPLICATE_MESSAGE_INDEX_REASON = "Duplicate message index, possible replay attack %1$s"; - public static final String ERROR_MISSING_PROPERTY_REASON = "No '%1$s' property. Cannot prevent unknown-key attack"; - public static final String UNKNOWN_DEVICES_REASON = "This room contains unknown devices which have not been verified.\n" + - "We strongly recommend you verify them before continuing."; - public static final String NO_MORE_ALGORITHM_REASON = "Room was previously configured to use encryption, but is no longer." + - " Perhaps the homeserver is hiding the configuration event."; - - /** - * Describe the error with more details - */ - private String mDetailedErrorDescription = null; - - /** - * Data exception. - * Some exceptions provide some data to describe the exception - */ - public Object mExceptionData = null; - - /** - * Create a crypto error - * - * @param code the error code (see XX_ERROR_CODE) - * @param shortErrorDescription the short error description - * @param detailedErrorDescription the detailed error description - */ - public MXCryptoError(String code, String shortErrorDescription, String detailedErrorDescription) { - errcode = code; - error = shortErrorDescription; - mDetailedErrorDescription = detailedErrorDescription; - } - - /** - * Create a crypto error - * - * @param code the error code (see XX_ERROR_CODE) - * @param shortErrorDescription the short error description - * @param detailedErrorDescription the detailed error description - * @param exceptionData the exception data - */ - public MXCryptoError(String code, String shortErrorDescription, String detailedErrorDescription, Object exceptionData) { - errcode = code; - error = shortErrorDescription; - mDetailedErrorDescription = detailedErrorDescription; - mExceptionData = exceptionData; - } - - /** - * @return true if the current error is an olm one. - */ - public boolean isOlmError() { - return TextUtils.equals(OLM_ERROR_CODE, errcode); - } - - - /** - * @return the detailed error description - */ - public String getDetailedErrorDescription() { - if (TextUtils.isEmpty(mDetailedErrorDescription)) { - return error; - } - - return mDetailedErrorDescription; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXDecryptionException.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXDecryptionException.java deleted file mode 100644 index 78ab57f7..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXDecryptionException.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.crypto; - -/** - * This class represents a decryption exception - */ -public class MXDecryptionException extends Exception { - - /** - * Describe the decryption error. - */ - private MXCryptoError mCryptoError; - - /** - * Constructor - * - * @param cryptoError the linked crypto error - */ - public MXDecryptionException(MXCryptoError cryptoError) { - mCryptoError = cryptoError; - } - - /** - * @return the linked crypto error - */ - public MXCryptoError getCryptoError() { - return mCryptoError; - } - - @Override - public String getMessage() { - if (null != mCryptoError) { - return mCryptoError.getMessage(); - } - - return super.getMessage(); - } - - @Override - public String getLocalizedMessage() { - if (null != mCryptoError) { - return mCryptoError.getLocalizedMessage(); - } - return super.getLocalizedMessage(); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXDeviceList.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXDeviceList.java deleted file mode 100755 index 230cd2a5..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXDeviceList.java +++ /dev/null @@ -1,835 +0,0 @@ -/* - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.crypto; - -import android.text.TextUtils; - -import im.vector.matrix.android.internal.legacy.MXPatterns; -import im.vector.matrix.android.internal.legacy.MXSession; -import im.vector.matrix.android.internal.legacy.crypto.data.MXDeviceInfo; -import im.vector.matrix.android.internal.legacy.crypto.data.MXUsersDevicesMap; -import im.vector.matrix.android.internal.legacy.data.cryptostore.IMXCryptoStore; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.KeysQueryResponse; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -public class MXDeviceList { - private static final String LOG_TAG = MXDeviceList.class.getSimpleName(); - - /** - * State transition diagram for DeviceList.deviceTrackingStatus - *

- * | - * stopTrackingDeviceList V - * +---------------------> NOT_TRACKED - * | | - * +<--------------------+ | startTrackingDeviceList - * | | V - * | +-------------> PENDING_DOWNLOAD <--------------------+-+ - * | | ^ | | | - * | | restart download | | start download | | invalidateUserDeviceList - * | | client failed | | | | - * | | | V | | - * | +------------ DOWNLOAD_IN_PROGRESS -------------------+ | - * | | | | - * +<-------------------+ | download successful | - * ^ V | - * +----------------------- UP_TO_DATE ------------------------+ - **/ - - public static final int TRACKING_STATUS_NOT_TRACKED = -1; - public static final int TRACKING_STATUS_PENDING_DOWNLOAD = 1; - public static final int TRACKING_STATUS_DOWNLOAD_IN_PROGRESS = 2; - public static final int TRACKING_STATUS_UP_TO_DATE = 3; - public static final int TRACKING_STATUS_UNREACHABLE_SERVER = 4; - - // keys in progress - private final Set mUserKeyDownloadsInProgress = new HashSet<>(); - - // HS not ready for retry - private final Set mNotReadyToRetryHS = new HashSet<>(); - - // indexed by UserId - private final Map mPendingDownloadKeysRequestToken = new HashMap<>(); - - // download keys queue - class DownloadKeysPromise { - // list of remain pending device keys - final List mPendingUserIdsList; - - // the unfiltered user ids list - final List mUserIdsList; - - // the request callback - final ApiCallback> mCallback; - - /** - * Creator - * - * @param userIds the user ids list - * @param callback the asynchronous callback - */ - DownloadKeysPromise(List userIds, ApiCallback> callback) { - mPendingUserIdsList = new ArrayList<>(userIds); - mUserIdsList = new ArrayList<>(userIds); - mCallback = callback; - } - } - - // pending queues list - private final List mDownloadKeysQueues = new ArrayList<>(); - - private final MXCrypto mxCrypto; - - private final MXSession mxSession; - - private final IMXCryptoStore mCryptoStore; - - // tells if there is a download keys request in progress - private boolean mIsDownloadingKeys = false; - - /** - * Constructor - * - * @param session the session - * @param crypto the crypto session - */ - public MXDeviceList(MXSession session, MXCrypto crypto) { - mxSession = session; - mxCrypto = crypto; - mCryptoStore = crypto.getCryptoStore(); - - boolean isUpdated = false; - - Map deviceTrackingStatuses = mCryptoStore.getDeviceTrackingStatuses(); - for (String userId : deviceTrackingStatuses.keySet()) { - int status = deviceTrackingStatuses.get(userId); - - if ((TRACKING_STATUS_DOWNLOAD_IN_PROGRESS == status) || (TRACKING_STATUS_UNREACHABLE_SERVER == status)) { - // if a download was in progress when we got shut down, it isn't any more. - deviceTrackingStatuses.put(userId, TRACKING_STATUS_PENDING_DOWNLOAD); - isUpdated = true; - } - } - - if (isUpdated) { - mCryptoStore.saveDeviceTrackingStatuses(deviceTrackingStatuses); - } - } - - /** - * Tells if the key downloads should be tried - * - * @param userId the userId - * @return true if the keys download can be retrieved - */ - private boolean canRetryKeysDownload(String userId) { - boolean res = false; - - if (!TextUtils.isEmpty(userId) && userId.contains(":")) { - try { - synchronized (mNotReadyToRetryHS) { - res = !mNotReadyToRetryHS.contains(userId.substring(userId.lastIndexOf(":") + 1)); - } - } catch (Exception e) { - Log.e(LOG_TAG, "## canRetryKeysDownload() failed : " + e.getMessage(), e); - } - } - - return res; - } - - /** - * Add a download keys promise - * - * @param userIds the user ids list - * @param callback the asynchronous callback - * @return the filtered user ids list i.e the one which require a remote request - */ - private List addDownloadKeysPromise(List userIds, ApiCallback> callback) { - if (null != userIds) { - List filteredUserIds = new ArrayList<>(); - List invalidUserIds = new ArrayList<>(); - - for (String userId : userIds) { - if (MXPatterns.isUserId(userId)) { - filteredUserIds.add(userId); - } else { - Log.e(LOG_TAG, "## userId " + userId + "is not a valid user id"); - invalidUserIds.add(userId); - } - } - - synchronized (mUserKeyDownloadsInProgress) { - filteredUserIds.removeAll(mUserKeyDownloadsInProgress); - mUserKeyDownloadsInProgress.addAll(userIds); - // got some email addresses instead of matrix ids - mUserKeyDownloadsInProgress.removeAll(invalidUserIds); - userIds.removeAll(invalidUserIds); - } - - mDownloadKeysQueues.add(new DownloadKeysPromise(userIds, callback)); - - return filteredUserIds; - } else { - return null; - } - } - - /** - * Clear the unavailable server lists - */ - private void clearUnavailableServersList() { - synchronized (mNotReadyToRetryHS) { - mNotReadyToRetryHS.clear(); - } - } - - /** - * Mark the cached device list for the given user outdated - * flag the given user for device-list tracking, if they are not already. - * - * @param userIds the user ids list - */ - public void startTrackingDeviceList(List userIds) { - if (null != userIds) { - boolean isUpdated = false; - Map deviceTrackingStatuses = mCryptoStore.getDeviceTrackingStatuses(); - - for (String userId : userIds) { - if (!deviceTrackingStatuses.containsKey(userId) || (TRACKING_STATUS_NOT_TRACKED == deviceTrackingStatuses.get(userId))) { - Log.d(LOG_TAG, "## startTrackingDeviceList() : Now tracking device list for " + userId); - deviceTrackingStatuses.put(userId, TRACKING_STATUS_PENDING_DOWNLOAD); - isUpdated = true; - } - } - - if (isUpdated) { - mCryptoStore.saveDeviceTrackingStatuses(deviceTrackingStatuses); - } - } - } - - /** - * Update the devices list statuses - * - * @param changed the user ids list which have new devices - * @param left the user ids list which left a room - */ - public void handleDeviceListsChanges(List changed, List left) { - boolean isUpdated = false; - Map deviceTrackingStatuses = mCryptoStore.getDeviceTrackingStatuses(); - - if ((null != changed) && (0 != changed.size())) { - clearUnavailableServersList(); - - for (String userId : changed) { - if (deviceTrackingStatuses.containsKey(userId)) { - Log.d(LOG_TAG, "## invalidateUserDeviceList() : Marking device list outdated for " + userId); - deviceTrackingStatuses.put(userId, TRACKING_STATUS_PENDING_DOWNLOAD); - isUpdated = true; - } - } - } - - if ((null != left) && (0 != left.size())) { - clearUnavailableServersList(); - - for (String userId : left) { - if (deviceTrackingStatuses.containsKey(userId)) { - Log.d(LOG_TAG, "## invalidateUserDeviceList() : No longer tracking device list for " + userId); - deviceTrackingStatuses.put(userId, TRACKING_STATUS_NOT_TRACKED); - isUpdated = true; - } - } - } - - if (isUpdated) { - mCryptoStore.saveDeviceTrackingStatuses(deviceTrackingStatuses); - } - } - - /** - * This will flag each user whose devices we are tracking as in need of an - * + update - */ - public void invalidateAllDeviceLists() { - handleDeviceListsChanges(new ArrayList<>(mCryptoStore.getDeviceTrackingStatuses().keySet()), null); - } - - /** - * The keys download failed - * - * @param userIds the user ids list - */ - private void onKeysDownloadFailed(final List userIds) { - if (null != userIds) { - synchronized (mUserKeyDownloadsInProgress) { - Map deviceTrackingStatuses = mCryptoStore.getDeviceTrackingStatuses(); - - for (String userId : userIds) { - mUserKeyDownloadsInProgress.remove(userId); - deviceTrackingStatuses.put(userId, TRACKING_STATUS_PENDING_DOWNLOAD); - } - - mCryptoStore.saveDeviceTrackingStatuses(deviceTrackingStatuses); - } - } - - mIsDownloadingKeys = false; - } - - /** - * The keys download succeeded. - * - * @param userIds the userIds list - * @param failures the failure map. - */ - private void onKeysDownloadSucceed(List userIds, Map> failures) { - if (null != failures) { - Set keys = failures.keySet(); - - for (String k : keys) { - Map value = failures.get(k); - - if (value.containsKey("status")) { - Object statusCodeAsVoid = value.get("status"); - int statusCode = 0; - - if (statusCodeAsVoid instanceof Double) { - statusCode = ((Double) statusCodeAsVoid).intValue(); - } else if (statusCodeAsVoid instanceof Integer) { - statusCode = ((Integer) statusCodeAsVoid).intValue(); - } - - if (statusCode == 503) { - synchronized (mNotReadyToRetryHS) { - mNotReadyToRetryHS.add(k); - } - } - } - } - } - - Map deviceTrackingStatuses = mCryptoStore.getDeviceTrackingStatuses(); - - if (null != userIds) { - if (mDownloadKeysQueues.size() > 0) { - List promisesToRemove = new ArrayList<>(); - - for (DownloadKeysPromise promise : mDownloadKeysQueues) { - promise.mPendingUserIdsList.removeAll(userIds); - - if (promise.mPendingUserIdsList.size() == 0) { - // private members - final MXUsersDevicesMap usersDevicesInfoMap = new MXUsersDevicesMap<>(); - - for (String userId : promise.mUserIdsList) { - Map devices = mCryptoStore.getUserDevices(userId); - if (null == devices) { - if (canRetryKeysDownload(userId)) { - deviceTrackingStatuses.put(userId, TRACKING_STATUS_PENDING_DOWNLOAD); - Log.e(LOG_TAG, "failed to retry the devices of " + userId + " : retry later"); - } else { - if (deviceTrackingStatuses.containsKey(userId) - && (TRACKING_STATUS_DOWNLOAD_IN_PROGRESS == deviceTrackingStatuses.get(userId))) { - deviceTrackingStatuses.put(userId, TRACKING_STATUS_UNREACHABLE_SERVER); - Log.e(LOG_TAG, "failed to retry the devices of " + userId + " : the HS is not available"); - } - } - } else { - if (deviceTrackingStatuses.containsKey(userId) - && (TRACKING_STATUS_DOWNLOAD_IN_PROGRESS == deviceTrackingStatuses.get(userId))) { - // we didn't get any new invalidations since this download started: - // this user's device list is now up to date. - deviceTrackingStatuses.put(userId, TRACKING_STATUS_UP_TO_DATE); - Log.d(LOG_TAG, "Device list for " + userId + " now up to date"); - } - - // And the response result - usersDevicesInfoMap.setObjects(devices, userId); - } - } - - if (!mxCrypto.hasBeenReleased()) { - final ApiCallback> callback = promise.mCallback; - - if (null != callback) { - mxCrypto.getUIHandler().post(new Runnable() { - @Override - public void run() { - callback.onSuccess(usersDevicesInfoMap); - } - }); - } - } - promisesToRemove.add(promise); - } - } - mDownloadKeysQueues.removeAll(promisesToRemove); - } - - for (String userId : userIds) { - mUserKeyDownloadsInProgress.remove(userId); - } - - mCryptoStore.saveDeviceTrackingStatuses(deviceTrackingStatuses); - } - - mIsDownloadingKeys = false; - } - - /** - * Download the device keys for a list of users and stores the keys in the MXStore. - * It must be called in getEncryptingThreadHandler() thread. - * The callback is called in the UI thread. - * - * @param userIds The users to fetch. - * @param forceDownload Always download the keys even if cached. - * @param callback the asynchronous callback - */ - public void downloadKeys(List userIds, boolean forceDownload, final ApiCallback> callback) { - Log.d(LOG_TAG, "## downloadKeys() : forceDownload " + forceDownload + " : " + userIds); - - // Map from userid -> deviceid -> DeviceInfo - final MXUsersDevicesMap stored = new MXUsersDevicesMap<>(); - - // List of user ids we need to download keys for - final List downloadUsers = new ArrayList<>(); - - if (null != userIds) { - if (forceDownload) { - downloadUsers.addAll(userIds); - } else { - for (String userId : userIds) { - Integer status = mCryptoStore.getDeviceTrackingStatus(userId, TRACKING_STATUS_NOT_TRACKED); - - // downloading keys ->the keys download won't be triggered twice but the callback requires the dedicated keys - // not yet retrieved - if (mUserKeyDownloadsInProgress.contains(userId) - || ((TRACKING_STATUS_UP_TO_DATE != status) && (TRACKING_STATUS_UNREACHABLE_SERVER != status))) { - downloadUsers.add(userId); - } else { - Map devices = mCryptoStore.getUserDevices(userId); - - // should always be true - if (null != devices) { - stored.setObjects(devices, userId); - } else { - downloadUsers.add(userId); - } - } - } - } - } - - if (0 == downloadUsers.size()) { - Log.d(LOG_TAG, "## downloadKeys() : no new user device"); - - if (null != callback) { - mxCrypto.getUIHandler().post(new Runnable() { - @Override - public void run() { - callback.onSuccess(stored); - } - }); - } - } else { - Log.d(LOG_TAG, "## downloadKeys() : starts"); - final long t0 = System.currentTimeMillis(); - - doKeyDownloadForUsers(downloadUsers, new ApiCallback>() { - public void onSuccess(MXUsersDevicesMap usersDevicesInfoMap) { - Log.d(LOG_TAG, "## downloadKeys() : doKeyDownloadForUsers succeeds after " + (System.currentTimeMillis() - t0) + " ms"); - - usersDevicesInfoMap.addEntriesFromMap(stored); - - if (null != callback) { - callback.onSuccess(usersDevicesInfoMap); - } - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "## downloadKeys() : doKeyDownloadForUsers onNetworkError " + e.getMessage(), e); - if (null != callback) { - callback.onNetworkError(e); - } - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "## downloadKeys() : doKeyDownloadForUsers onMatrixError " + e.getMessage()); - if (null != callback) { - callback.onMatrixError(e); - } - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "## downloadKeys() : doKeyDownloadForUsers onUnexpectedError " + e.getMessage(), e); - if (null != callback) { - callback.onUnexpectedError(e); - } - } - }); - } - } - - /** - * Download the devices keys for a set of users. - * It must be called in getEncryptingThreadHandler() thread. - * The callback is called in the UI thread. - * - * @param downloadUsers the user ids list - * @param callback the asynchronous callback - */ - private void doKeyDownloadForUsers(final List downloadUsers, final ApiCallback> callback) { - Log.d(LOG_TAG, "## doKeyDownloadForUsers() : doKeyDownloadForUsers " + downloadUsers); - - // get the user ids which did not already trigger a keys download - final List filteredUsers = addDownloadKeysPromise(downloadUsers, callback); - - // if there is no new keys request - if (0 == filteredUsers.size()) { - // trigger nothing - return; - } - - // sanity check - if ((null == mxSession.getDataHandler()) || (null == mxSession.getDataHandler().getStore())) { - return; - } - - mIsDownloadingKeys = true; - - // track the race condition while sending requests - // we defines a tag for each request - // and test if the response is the latest request one - final String downloadToken = filteredUsers.hashCode() + " " + System.currentTimeMillis(); - - for (String userId : filteredUsers) { - mPendingDownloadKeysRequestToken.put(userId, downloadToken); - } - - mxSession.getCryptoRestClient() - .downloadKeysForUsers(filteredUsers, mxSession.getDataHandler().getStore().getEventStreamToken(), new ApiCallback() { - @Override - public void onSuccess(final KeysQueryResponse keysQueryResponse) { - mxCrypto.getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - Log.d(LOG_TAG, "## doKeyDownloadForUsers() : Got keys for " + filteredUsers.size() + " users"); - MXDeviceInfo myDevice = mxCrypto.getMyDevice(); - IMXCryptoStore cryptoStore = mxCrypto.getCryptoStore(); - - List userIdsList = new ArrayList<>(filteredUsers); - - for (String userId : userIdsList) { - // test if the response is the latest request one - if (!TextUtils.equals(mPendingDownloadKeysRequestToken.get(userId), downloadToken)) { - Log.e(LOG_TAG, "## doKeyDownloadForUsers() : Another update in the queue for " - + userId + " not marking up-to-date"); - filteredUsers.remove(userId); - } else { - Map devices = keysQueryResponse.deviceKeys.get(userId); - - Log.d(LOG_TAG, "## doKeyDownloadForUsers() : Got keys for " + userId + " : " + devices); - - if (null != devices) { - Map mutableDevices = new HashMap<>(devices); - List deviceIds = new ArrayList<>(mutableDevices.keySet()); - - for (String deviceId : deviceIds) { - // the user has been logged out - if (null == cryptoStore) { - break; - } - - // Get the potential previously store device keys for this device - MXDeviceInfo previouslyStoredDeviceKeys = cryptoStore.getUserDevice(deviceId, userId); - MXDeviceInfo deviceInfo = mutableDevices.get(deviceId); - - // in some race conditions (like unit tests) - // the self device must be seen as verified - if (TextUtils.equals(deviceInfo.deviceId, myDevice.deviceId) - && TextUtils.equals(userId, myDevice.userId)) { - deviceInfo.mVerified = MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED; - } - - // Validate received keys - if (!validateDeviceKeys(deviceInfo, userId, deviceId, previouslyStoredDeviceKeys)) { - // New device keys are not valid. Do not store them - mutableDevices.remove(deviceId); - - if (null != previouslyStoredDeviceKeys) { - // But keep old validated ones if any - mutableDevices.put(deviceId, previouslyStoredDeviceKeys); - } - } else if (null != previouslyStoredDeviceKeys) { - // The verified status is not sync'ed with hs. - // This is a client side information, valid only for this client. - // So, transfer its previous value - mutableDevices.get(deviceId).mVerified = previouslyStoredDeviceKeys.mVerified; - } - } - - // Update the store - // Note that devices which aren't in the response will be removed from the stores - cryptoStore.storeUserDevices(userId, mutableDevices); - } - - // the response is the latest request one - mPendingDownloadKeysRequestToken.remove(userId); - } - } - - onKeysDownloadSucceed(filteredUsers, keysQueryResponse.failures); - } - }); - } - - private void onFailed() { - mxCrypto.getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - List userIdsList = new ArrayList<>(filteredUsers); - - // test if the response is the latest request one - for (String userId : userIdsList) { - if (!TextUtils.equals(mPendingDownloadKeysRequestToken.get(userId), downloadToken)) { - Log.e(LOG_TAG, "## doKeyDownloadForUsers() : Another update in the queue for " + userId + " not marking up-to-date"); - filteredUsers.remove(userId); - } else { - // the response is the latest request one - mPendingDownloadKeysRequestToken.remove(userId); - } - } - - onKeysDownloadFailed(filteredUsers); - } - }); - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "##doKeyDownloadForUsers() : onNetworkError " + e.getMessage(), e); - - onFailed(); - - if (null != callback) { - callback.onNetworkError(e); - } - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "##doKeyDownloadForUsers() : onMatrixError " + e.getMessage()); - - onFailed(); - - if (null != callback) { - callback.onMatrixError(e); - } - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "##doKeyDownloadForUsers() : onUnexpectedError " + e.getMessage(), e); - - onFailed(); - - if (null != callback) { - callback.onUnexpectedError(e); - } - } - }); - } - - /** - * Validate device keys. - * This method must called on getEncryptingThreadHandler() thread. - * - * @param deviceKeys the device keys to validate. - * @param userId the id of the user of the device. - * @param deviceId the id of the device. - * @param previouslyStoredDeviceKeys the device keys we received before for this device - * @return true if succeeds - */ - private boolean validateDeviceKeys(MXDeviceInfo deviceKeys, String userId, String deviceId, MXDeviceInfo previouslyStoredDeviceKeys) { - if (null == deviceKeys) { - Log.e(LOG_TAG, "## validateDeviceKeys() : deviceKeys is null from " + userId + ":" + deviceId); - return false; - } - - if (null == deviceKeys.keys) { - Log.e(LOG_TAG, "## validateDeviceKeys() : deviceKeys.keys is null from " + userId + ":" + deviceId); - return false; - } - - if (null == deviceKeys.signatures) { - Log.e(LOG_TAG, "## validateDeviceKeys() : deviceKeys.signatures is null from " + userId + ":" + deviceId); - return false; - } - - // Check that the user_id and device_id in the received deviceKeys are correct - if (!TextUtils.equals(deviceKeys.userId, userId)) { - Log.e(LOG_TAG, "## validateDeviceKeys() : Mismatched user_id " + deviceKeys.userId + " from " + userId + ":" + deviceId); - return false; - } - - if (!TextUtils.equals(deviceKeys.deviceId, deviceId)) { - Log.e(LOG_TAG, "## validateDeviceKeys() : Mismatched device_id " + deviceKeys.deviceId + " from " + userId + ":" + deviceId); - return false; - } - - String signKeyId = "ed25519:" + deviceKeys.deviceId; - String signKey = deviceKeys.keys.get(signKeyId); - - if (null == signKey) { - Log.e(LOG_TAG, "## validateDeviceKeys() : Device " + userId + ":" + deviceKeys.deviceId + " has no ed25519 key"); - return false; - } - - Map signatureMap = deviceKeys.signatures.get(userId); - - if (null == signatureMap) { - Log.e(LOG_TAG, "## validateDeviceKeys() : Device " + userId + ":" + deviceKeys.deviceId + " has no map for " + userId); - return false; - } - - String signature = signatureMap.get(signKeyId); - - if (null == signature) { - Log.e(LOG_TAG, "## validateDeviceKeys() : Device " + userId + ":" + deviceKeys.deviceId + " is not signed"); - return false; - } - - boolean isVerified = false; - String errorMessage = null; - - try { - mxCrypto.getOlmDevice().verifySignature(signKey, deviceKeys.signalableJSONDictionary(), signature); - isVerified = true; - } catch (Exception e) { - errorMessage = e.getMessage(); - } - - if (!isVerified) { - Log.e(LOG_TAG, "## validateDeviceKeys() : Unable to verify signature on device " + userId + ":" - + deviceKeys.deviceId + " with error " + errorMessage); - return false; - } - - if (null != previouslyStoredDeviceKeys) { - if (!TextUtils.equals(previouslyStoredDeviceKeys.fingerprint(), signKey)) { - // This should only happen if the list has been MITMed; we are - // best off sticking with the original keys. - // - // Should we warn the user about it somehow? - Log.e(LOG_TAG, "## validateDeviceKeys() : WARNING:Ed25519 key for device " + userId + ":" - + deviceKeys.deviceId + " has changed : " - + previouslyStoredDeviceKeys.fingerprint() + " -> " + signKey); - - Log.e(LOG_TAG, "## validateDeviceKeys() : " + previouslyStoredDeviceKeys + " -> " + deviceKeys); - Log.e(LOG_TAG, "## validateDeviceKeys() : " + previouslyStoredDeviceKeys.keys + " -> " + deviceKeys.keys); - - return false; - } - } - - return true; - } - - /** - * Start device queries for any users who sent us an m.new_device recently - * This method must be called on getEncryptingThreadHandler() thread. - */ - public void refreshOutdatedDeviceLists() { - final List users = new ArrayList<>(); - - Map deviceTrackingStatuses = mCryptoStore.getDeviceTrackingStatuses(); - - for (String userId : deviceTrackingStatuses.keySet()) { - if (TRACKING_STATUS_PENDING_DOWNLOAD == deviceTrackingStatuses.get(userId)) { - users.add(userId); - } - } - - if (users.size() == 0) { - return; - } - - if (mIsDownloadingKeys) { - // request already in progress - do nothing. (We will automatically - // make another request if there are more users with outdated - // device lists when the current request completes). - return; - } - - // update the statuses - for (String userId : users) { - Integer status = deviceTrackingStatuses.get(userId); - - if ((null != status) && (TRACKING_STATUS_PENDING_DOWNLOAD == status)) { - deviceTrackingStatuses.put(userId, TRACKING_STATUS_DOWNLOAD_IN_PROGRESS); - } - } - - mCryptoStore.saveDeviceTrackingStatuses(deviceTrackingStatuses); - - doKeyDownloadForUsers(users, new ApiCallback>() { - @Override - public void onSuccess(final MXUsersDevicesMap response) { - mxCrypto.getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - Log.d(LOG_TAG, "## refreshOutdatedDeviceLists() : done"); - } - }); - } - - private void onError(String error) { - Log.e(LOG_TAG, "## refreshOutdatedDeviceLists() : ERROR updating device keys for users " + users + " : " + error); - } - - @Override - public void onNetworkError(final Exception e) { - onError(e.getMessage()); - } - - @Override - public void onMatrixError(final MatrixError e) { - onError(e.getMessage()); - } - - @Override - public void onUnexpectedError(final Exception e) { - onError(e.getMessage()); - } - }); - } -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXEncryptedAttachments.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXEncryptedAttachments.java deleted file mode 100755 index cd8e736c..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXEncryptedAttachments.java +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.crypto; - -import android.text.TextUtils; -import android.util.Base64; - -import im.vector.matrix.android.internal.legacy.rest.model.crypto.EncryptedFileInfo; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.EncryptedFileKey; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.io.Serializable; -import java.security.MessageDigest; -import java.security.SecureRandom; -import java.util.Arrays; -import java.util.HashMap; - -import javax.crypto.Cipher; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; - -public class MXEncryptedAttachments implements Serializable { - private static final String LOG_TAG = MXEncryptedAttachments.class.getSimpleName(); - - private static final int CRYPTO_BUFFER_SIZE = 32 * 1024; - private static final String CIPHER_ALGORITHM = "AES/CTR/NoPadding"; - private static final String SECRET_KEY_SPEC_ALGORITHM = "AES"; - private static final String MESSAGE_DIGEST_ALGORITHM = "SHA-256"; - - /** - * Define the result of an encryption file - */ - public static class EncryptionResult { - public EncryptedFileInfo mEncryptedFileInfo; - public InputStream mEncryptedStream; - - public EncryptionResult() { - } - } - - /*** - * Encrypt an attachment stream. - * @param attachmentStream the attachment stream - * @param mimetype the mime type - * @return the encryption file info - */ - public static EncryptionResult encryptAttachment(InputStream attachmentStream, String mimetype) { - long t0 = System.currentTimeMillis(); - SecureRandom secureRandom = new SecureRandom(); - - // generate a random iv key - // Half of the IV is random, the lower order bits are zeroed - // such that the counter never wraps. - // See https://github.com/matrix-org/matrix-ios-kit/blob/3dc0d8e46b4deb6669ed44f72ad79be56471354c/MatrixKit/Models/Room/MXEncryptedAttachments.m#L75 - byte[] initVectorBytes = new byte[16]; - Arrays.fill(initVectorBytes, (byte) 0); - - byte[] ivRandomPart = new byte[8]; - secureRandom.nextBytes(ivRandomPart); - - System.arraycopy(ivRandomPart, 0, initVectorBytes, 0, ivRandomPart.length); - - byte[] key = new byte[32]; - secureRandom.nextBytes(key); - - ByteArrayOutputStream outStream = new ByteArrayOutputStream(); - - try { - Cipher encryptCipher = Cipher.getInstance(CIPHER_ALGORITHM); - SecretKeySpec secretKeySpec = new SecretKeySpec(key, SECRET_KEY_SPEC_ALGORITHM); - IvParameterSpec ivParameterSpec = new IvParameterSpec(initVectorBytes); - encryptCipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec); - - MessageDigest messageDigest = MessageDigest.getInstance(MESSAGE_DIGEST_ALGORITHM); - - byte[] data = new byte[CRYPTO_BUFFER_SIZE]; - int read; - byte[] encodedBytes; - - while (-1 != (read = attachmentStream.read(data))) { - encodedBytes = encryptCipher.update(data, 0, read); - messageDigest.update(encodedBytes, 0, encodedBytes.length); - outStream.write(encodedBytes); - } - - // encrypt the latest chunk - encodedBytes = encryptCipher.doFinal(); - messageDigest.update(encodedBytes, 0, encodedBytes.length); - outStream.write(encodedBytes); - - EncryptionResult result = new EncryptionResult(); - result.mEncryptedFileInfo = new EncryptedFileInfo(); - result.mEncryptedFileInfo.key = new EncryptedFileKey(); - result.mEncryptedFileInfo.mimetype = mimetype; - result.mEncryptedFileInfo.key.alg = "A256CTR"; - result.mEncryptedFileInfo.key.ext = true; - result.mEncryptedFileInfo.key.key_ops = Arrays.asList("encrypt", "decrypt"); - result.mEncryptedFileInfo.key.kty = "oct"; - result.mEncryptedFileInfo.key.k = base64ToBase64Url(Base64.encodeToString(key, Base64.DEFAULT)); - result.mEncryptedFileInfo.iv = Base64.encodeToString(initVectorBytes, Base64.DEFAULT).replace("\n", "").replace("=", ""); - result.mEncryptedFileInfo.v = "v2"; - - result.mEncryptedFileInfo.hashes = new HashMap<>(); - result.mEncryptedFileInfo.hashes.put("sha256", base64ToUnpaddedBase64(Base64.encodeToString(messageDigest.digest(), Base64.DEFAULT))); - - result.mEncryptedStream = new ByteArrayInputStream(outStream.toByteArray()); - outStream.close(); - - Log.d(LOG_TAG, "Encrypt in " + (System.currentTimeMillis() - t0) + " ms"); - return result; - } catch (OutOfMemoryError oom) { - Log.e(LOG_TAG, "## encryptAttachment failed " + oom.getMessage(), oom); - } catch (Exception e) { - Log.e(LOG_TAG, "## encryptAttachment failed " + e.getMessage(), e); - } - - try { - outStream.close(); - } catch (Exception e) { - Log.e(LOG_TAG, "## encryptAttachment() : fail to close outStream", e); - } - - return null; - } - - /** - * Decrypt an attachment - * - * @param attachmentStream the attachment stream - * @param encryptedFileInfo the encryption file info - * @return the decrypted attachment stream - */ - public static InputStream decryptAttachment(InputStream attachmentStream, EncryptedFileInfo encryptedFileInfo) { - // sanity checks - if ((null == attachmentStream) || (null == encryptedFileInfo)) { - Log.e(LOG_TAG, "## decryptAttachment() : null parameters"); - return null; - } - - if (TextUtils.isEmpty(encryptedFileInfo.iv) - || (null == encryptedFileInfo.key) - || (null == encryptedFileInfo.hashes) - || !encryptedFileInfo.hashes.containsKey("sha256")) { - Log.e(LOG_TAG, "## decryptAttachment() : some fields are not defined"); - return null; - } - - if (!TextUtils.equals(encryptedFileInfo.key.alg, "A256CTR") - || !TextUtils.equals(encryptedFileInfo.key.kty, "oct") - || TextUtils.isEmpty(encryptedFileInfo.key.k)) { - Log.e(LOG_TAG, "## decryptAttachment() : invalid key fields"); - return null; - } - - // detect if there is no data to decrypt - try { - if (0 == attachmentStream.available()) { - return new ByteArrayInputStream(new byte[0]); - } - } catch (Exception e) { - Log.e(LOG_TAG, "Fail to retrieve the file size", e); - } - - long t0 = System.currentTimeMillis(); - - ByteArrayOutputStream outStream = new ByteArrayOutputStream(); - - try { - byte[] key = Base64.decode(base64UrlToBase64(encryptedFileInfo.key.k), Base64.DEFAULT); - byte[] initVectorBytes = Base64.decode(encryptedFileInfo.iv, Base64.DEFAULT); - - Cipher decryptCipher = Cipher.getInstance(CIPHER_ALGORITHM); - SecretKeySpec secretKeySpec = new SecretKeySpec(key, SECRET_KEY_SPEC_ALGORITHM); - IvParameterSpec ivParameterSpec = new IvParameterSpec(initVectorBytes); - decryptCipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec); - - MessageDigest messageDigest = MessageDigest.getInstance(MESSAGE_DIGEST_ALGORITHM); - - int read; - byte[] data = new byte[CRYPTO_BUFFER_SIZE]; - byte[] decodedBytes; - - while (-1 != (read = attachmentStream.read(data))) { - messageDigest.update(data, 0, read); - decodedBytes = decryptCipher.update(data, 0, read); - outStream.write(decodedBytes); - } - - // decrypt the last chunk - decodedBytes = decryptCipher.doFinal(); - outStream.write(decodedBytes); - - String currentDigestValue = base64ToUnpaddedBase64(Base64.encodeToString(messageDigest.digest(), Base64.DEFAULT)); - - if (!TextUtils.equals(encryptedFileInfo.hashes.get("sha256"), currentDigestValue)) { - Log.e(LOG_TAG, "## decryptAttachment() : Digest value mismatch"); - outStream.close(); - return null; - } - - InputStream decryptedStream = new ByteArrayInputStream(outStream.toByteArray()); - outStream.close(); - - Log.d(LOG_TAG, "Decrypt in " + (System.currentTimeMillis() - t0) + " ms"); - - return decryptedStream; - } catch (OutOfMemoryError oom) { - Log.e(LOG_TAG, "## decryptAttachment() : failed " + oom.getMessage(), oom); - } catch (Exception e) { - Log.e(LOG_TAG, "## decryptAttachment() : failed " + e.getMessage(), e); - } - - try { - outStream.close(); - } catch (Exception closeException) { - Log.e(LOG_TAG, "## decryptAttachment() : fail to close the file", closeException); - } - - return null; - } - - /** - * Base64 URL conversion methods - */ - - private static String base64UrlToBase64(String base64Url) { - if (null != base64Url) { - base64Url = base64Url.replaceAll("-", "+"); - base64Url = base64Url.replaceAll("_", "/"); - } - - return base64Url; - } - - private static String base64ToBase64Url(String base64) { - if (null != base64) { - base64 = base64.replaceAll("\n", ""); - base64 = base64.replaceAll("\\+", "-"); - base64 = base64.replaceAll("/", "_"); - base64 = base64.replaceAll("=", ""); - } - return base64; - } - - private static String base64ToUnpaddedBase64(String base64) { - if (null != base64) { - base64 = base64.replaceAll("\n", ""); - base64 = base64.replaceAll("=", ""); - } - - return base64; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXEventDecryptionResult.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXEventDecryptionResult.java deleted file mode 100644 index f2759c55..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXEventDecryptionResult.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.crypto; - -import com.google.gson.JsonElement; - -import java.util.ArrayList; -import java.util.List; - -/** - * The result of a (successful) call to decryptEvent. - */ -public class MXEventDecryptionResult { - - /** - * The plaintext payload for the event (typically containing "type" and "content" fields). - */ - public JsonElement mClearEvent; - - /** - * Key owned by the sender of this event. - * See MXEvent.senderKey. - */ - public String mSenderCurve25519Key; - - /** - * Ed25519 key claimed by the sender of this event. - * See MXEvent.claimedEd25519Key. - */ - public String mClaimedEd25519Key; - - /** - * List of curve25519 keys involved in telling us about the senderCurve25519Key and - * claimedEd25519Key. See MXEvent.forwardingCurve25519KeyChain. - */ - public List mForwardingCurve25519KeyChain = new ArrayList<>(); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXMegolmExportEncryption.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXMegolmExportEncryption.java deleted file mode 100755 index beb1b5df..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXMegolmExportEncryption.java +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright 2017 OpenMarket 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.matrix.android.internal.legacy.crypto; - -import android.text.TextUtils; -import android.util.Base64; - -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.io.ByteArrayOutputStream; -import java.security.SecureRandom; -import java.util.Arrays; - -import javax.crypto.Cipher; -import javax.crypto.Mac; -import javax.crypto.SecretKey; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; - -/** - * Utility class to import/export the crypto data - */ -public class MXMegolmExportEncryption { - private static final String LOG_TAG = MXMegolmExportEncryption.class.getSimpleName(); - - private static final String HEADER_LINE = "-----BEGIN MEGOLM SESSION DATA-----"; - private static final String TRAILER_LINE = "-----END MEGOLM SESSION DATA-----"; - // we split into lines before base64ing, because encodeBase64 doesn't deal - // terribly well with large arrays. - private static final int LINE_LENGTH = (72 * 4 / 3); - - // default iteration count to export the e2e keys - public static final int DEFAULT_ITERATION_COUNT = 500000; - - /** - * Convert a signed byte to a int value - * - * @param bVal the byte value to convert - * @return the matched int value - */ - private static int byteToInt(byte bVal) { - return bVal & 0xFF; - } - - /** - * Extract the AES key from the deriveKeys result. - * - * @param keyBits the deriveKeys result. - * @return the AES key - */ - private static byte[] getAesKey(byte[] keyBits) { - return Arrays.copyOfRange(keyBits, 0, 32); - } - - /** - * Extract the Hmac key from the deriveKeys result. - * - * @param keyBits the deriveKeys result. - * @return the Hmac key. - */ - private static byte[] getHmacKey(byte[] keyBits) { - return Arrays.copyOfRange(keyBits, 32, keyBits.length); - } - - /** - * Decrypt a megolm key file - * - * @param data the data to decrypt - * @param password the password. - * @return the decrypted output. - * @throws Exception the failure reason - */ - public static String decryptMegolmKeyFile(byte[] data, String password) throws Exception { - byte[] body = unpackMegolmKeyFile(data); - - // check we have a version byte - if ((null == body) || (body.length == 0)) { - Log.e(LOG_TAG, "## decryptMegolmKeyFile() : Invalid file: too short"); - throw new Exception("Invalid file: too short"); - } - - byte version = body[0]; - if (version != 1) { - Log.e(LOG_TAG, "## decryptMegolmKeyFile() : Invalid file: too short"); - throw new Exception("Unsupported version"); - } - - int ciphertextLength = body.length - (1 + 16 + 16 + 4 + 32); - if (ciphertextLength < 0) { - throw new Exception("Invalid file: too short"); - } - - if (TextUtils.isEmpty(password)) { - throw new Exception("Empty password is not supported"); - } - - byte[] salt = Arrays.copyOfRange(body, 1, 1 + 16); - byte[] iv = Arrays.copyOfRange(body, 17, 17 + 16); - int iterations = byteToInt(body[33]) << 24 | byteToInt(body[34]) << 16 | byteToInt(body[35]) << 8 | byteToInt(body[36]); - byte[] ciphertext = Arrays.copyOfRange(body, 37, 37 + ciphertextLength); - byte[] hmac = Arrays.copyOfRange(body, body.length - 32, body.length); - - byte[] deriveKey = deriveKeys(salt, iterations, password); - - byte[] toVerify = Arrays.copyOfRange(body, 0, body.length - 32); - - SecretKey macKey = new SecretKeySpec(getHmacKey(deriveKey), "HmacSHA256"); - Mac mac = Mac.getInstance("HmacSHA256"); - mac.init(macKey); - byte[] digest = mac.doFinal(toVerify); - - if (!Arrays.equals(hmac, digest)) { - Log.e(LOG_TAG, "## decryptMegolmKeyFile() : Authentication check failed: incorrect password?"); - throw new Exception("Authentication check failed: incorrect password?"); - } - - Cipher decryptCipher = Cipher.getInstance("AES/CTR/NoPadding"); - - SecretKeySpec secretKeySpec = new SecretKeySpec(getAesKey(deriveKey), "AES"); - IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); - decryptCipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec); - - ByteArrayOutputStream outStream = new ByteArrayOutputStream(); - outStream.write(decryptCipher.update(ciphertext)); - outStream.write(decryptCipher.doFinal()); - - String decodedString = new String(outStream.toByteArray(), "UTF-8"); - outStream.close(); - - return decodedString; - } - - /** - * Encrypt a string into the megolm export format. - * - * @param data the data to encrypt. - * @param password the password - * @return the encrypted data - * @throws Exception the failure reason - */ - public static byte[] encryptMegolmKeyFile(String data, String password) throws Exception { - return encryptMegolmKeyFile(data, password, DEFAULT_ITERATION_COUNT); - } - - /** - * Encrypt a string into the megolm export format. - * - * @param data the data to encrypt. - * @param password the password - * @param kdf_rounds the iteration count - * @return the encrypted data - * @throws Exception the failure reason - */ - public static byte[] encryptMegolmKeyFile(String data, String password, int kdf_rounds) throws Exception { - if (TextUtils.isEmpty(password)) { - throw new Exception("Empty password is not supported"); - } - - SecureRandom secureRandom = new SecureRandom(); - - byte[] salt = new byte[16]; - secureRandom.nextBytes(salt); - - byte[] iv = new byte[16]; - secureRandom.nextBytes(iv); - - // clear bit 63 of the salt to stop us hitting the 64-bit counter boundary - // (which would mean we wouldn't be able to decrypt on Android). The loss - // of a single bit of salt is a price we have to pay. - iv[9] &= 0x7f; - - byte[] deriveKey = deriveKeys(salt, kdf_rounds, password); - - Cipher decryptCipher = Cipher.getInstance("AES/CTR/NoPadding"); - - SecretKeySpec secretKeySpec = new SecretKeySpec(getAesKey(deriveKey), "AES"); - IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); - decryptCipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec); - - ByteArrayOutputStream outStream = new ByteArrayOutputStream(); - outStream.write(decryptCipher.update(data.getBytes("UTF-8"))); - outStream.write(decryptCipher.doFinal()); - - byte[] cipherArray = outStream.toByteArray(); - int bodyLength = (1 + salt.length + iv.length + 4 + cipherArray.length + 32); - - byte[] resultBuffer = new byte[bodyLength]; - int idx = 0; - resultBuffer[idx++] = 1; // version - - System.arraycopy(salt, 0, resultBuffer, idx, salt.length); - idx += salt.length; - - System.arraycopy(iv, 0, resultBuffer, idx, iv.length); - idx += iv.length; - - resultBuffer[idx++] = (byte) ((kdf_rounds >> 24) & 0xff); - resultBuffer[idx++] = (byte) ((kdf_rounds >> 16) & 0xff); - resultBuffer[idx++] = (byte) ((kdf_rounds >> 8) & 0xff); - resultBuffer[idx++] = (byte) ((kdf_rounds) & 0xff); - - System.arraycopy(cipherArray, 0, resultBuffer, idx, cipherArray.length); - idx += cipherArray.length; - - byte[] toSign = Arrays.copyOfRange(resultBuffer, 0, idx); - - SecretKey macKey = new SecretKeySpec(getHmacKey(deriveKey), "HmacSHA256"); - Mac mac = Mac.getInstance("HmacSHA256"); - mac.init(macKey); - byte[] digest = mac.doFinal(toSign); - System.arraycopy(digest, 0, resultBuffer, idx, digest.length); - - return packMegolmKeyFile(resultBuffer); - } - - /** - * Unbase64 an ascii-armoured megolm key file - * Strips the header and trailer lines, and unbase64s the content - * - * @param data the input data - * @return unbase64ed content - */ - private static byte[] unpackMegolmKeyFile(byte[] data) throws Exception { - String fileStr = new String(data, "UTF-8"); - - // look for the start line - int lineStart = 0; - - while (true) { - int lineEnd = fileStr.indexOf('\n', lineStart); - - if (lineEnd < 0) { - Log.e(LOG_TAG, "## unpackMegolmKeyFile() : Header line not found"); - throw new Exception("Header line not found"); - } - - String line = fileStr.substring(lineStart, lineEnd).trim(); - - // start the next line after the newline - lineStart = lineEnd + 1; - - if (TextUtils.equals(line, HEADER_LINE)) { - break; - } - } - - int dataStart = lineStart; - - // look for the end line - while (true) { - int lineEnd = fileStr.indexOf('\n', lineStart); - String line; - - if (lineEnd < 0) { - line = fileStr.substring(lineStart).trim(); - } else { - line = fileStr.substring(lineStart, lineEnd).trim(); - } - - if (TextUtils.equals(line, TRAILER_LINE)) { - break; - } - - if (lineEnd < 0) { - Log.e(LOG_TAG, "## unpackMegolmKeyFile() : Trailer line not found"); - throw new Exception("Trailer line not found"); - } - - // start the next line after the newline - lineStart = lineEnd + 1; - } - - int dataEnd = lineStart; - - // Receiving side - return Base64.decode(fileStr.substring(dataStart, dataEnd), Base64.DEFAULT); - } - - /** - * Pack the megolm data. - * - * @param data the data to pack. - * @return the packed data - * @throws Exception the failure reason. - */ - private static byte[] packMegolmKeyFile(byte[] data) throws Exception { - int nLines = (data.length + LINE_LENGTH - 1) / LINE_LENGTH; - - ByteArrayOutputStream outStream = new ByteArrayOutputStream(); - outStream.write(HEADER_LINE.getBytes()); - - int o = 0; - - for (int i = 1; i <= nLines; i++) { - outStream.write("\n".getBytes()); - - int len = Math.min(LINE_LENGTH, data.length - o); - outStream.write(Base64.encode(data, o, len, Base64.DEFAULT)); - o += LINE_LENGTH; - } - - outStream.write("\n".getBytes()); - outStream.write(TRAILER_LINE.getBytes()); - outStream.write("\n".getBytes()); - - return outStream.toByteArray(); - } - - /** - * Derive the AES and HMAC-SHA-256 keys for the file - * - * @param salt salt for pbkdf - * @param iterations number of pbkdf iterations - * @param password password - * @return the derived keys - */ - private static byte[] deriveKeys(byte[] salt, int iterations, String password) throws Exception { - Long t0 = System.currentTimeMillis(); - - // based on https://en.wikipedia.org/wiki/PBKDF2 algorithm - // it is simpler than the generic algorithm because the expected key length is equal to the mac key length. - // noticed as dklen/hlen - Mac prf = Mac.getInstance("HmacSHA512"); - prf.init(new SecretKeySpec(password.getBytes("UTF-8"), "HmacSHA512")); - - // 512 bits key length - byte[] key = new byte[64]; - byte[] Uc = new byte[64]; - - // U1 = PRF(Password, Salt || INT_32_BE(i)) - prf.update(salt); - byte[] int32BE = new byte[4]; - Arrays.fill(int32BE, (byte) 0); - int32BE[3] = (byte) 1; - prf.update(int32BE); - prf.doFinal(Uc, 0); - - // copy to the key - System.arraycopy(Uc, 0, key, 0, Uc.length); - - for (int index = 2; index <= iterations; index++) { - // Uc = PRF(Password, Uc-1) - prf.update(Uc); - prf.doFinal(Uc, 0); - - // F(Password, Salt, c, i) = U1 ^ U2 ^ ... ^ Uc - for (int byteIndex = 0; byteIndex < Uc.length; byteIndex++) { - key[byteIndex] ^= Uc[byteIndex]; - } - } - - Log.d(LOG_TAG, "## deriveKeys() : " + iterations + " in " + (System.currentTimeMillis() - t0) + " ms"); - - return key; - } -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXOlmDevice.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXOlmDevice.java deleted file mode 100755 index 0690f5dc..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXOlmDevice.java +++ /dev/null @@ -1,830 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.crypto; - -import android.text.TextUtils; - -import com.google.gson.JsonParser; - -import im.vector.matrix.android.internal.legacy.crypto.algorithms.MXDecryptionResult; -import im.vector.matrix.android.internal.legacy.crypto.data.MXOlmInboundGroupSession2; -import im.vector.matrix.android.internal.legacy.data.cryptostore.IMXCryptoStore; -import im.vector.matrix.android.internal.legacy.util.JsonUtils; -import im.vector.matrix.android.internal.legacy.util.Log; -import org.matrix.olm.OlmAccount; -import org.matrix.olm.OlmInboundGroupSession; -import org.matrix.olm.OlmMessage; -import org.matrix.olm.OlmOutboundGroupSession; -import org.matrix.olm.OlmSession; -import org.matrix.olm.OlmUtility; - -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -public class MXOlmDevice { - private static final String LOG_TAG = MXOlmDevice.class.getSimpleName(); - - // Curve25519 key for the account. - private String mDeviceCurve25519Key; - - // Ed25519 key for the account. - private String mDeviceEd25519Key; - - // The store where crypto data is saved. - private final IMXCryptoStore mStore; - - // The OLMKit account instance. - private OlmAccount mOlmAccount; - - // The OLMKit utility instance. - private OlmUtility mOlmUtility; - - // The outbound group session. - // They are not stored in 'store' to avoid to remember to which devices we sent the session key. - // Plus, in cryptography, it is good to refresh sessions from time to time. - // The key is the session id, the value the outbound group session. - private final Map mOutboundGroupSessionStore; - - // Store a set of decrypted message indexes for each group session. - // This partially mitigates a replay attack where a MITM resends a group - // message into the room. - // - // The Matrix SDK exposes events through MXEventTimelines. A developer can open several - // timelines from a same room so that a message can be decrypted several times but from - // a different timeline. - // So, store these message indexes per timeline id. - // - // The first level keys are timeline ids. - // The second level keys are strings of form "||" - // Values are true. - private final Map> mInboundGroupSessionMessageIndexes; - - /** - * inboundGroupSessionWithId error - */ - private MXCryptoError mInboundGroupSessionWithIdError = null; - - /** - * Constructor - * - * @param store the used store - */ - public MXOlmDevice(IMXCryptoStore store) { - mStore = store; - - // Retrieve the account from the store - mOlmAccount = mStore.getAccount(); - - if (null == mOlmAccount) { - Log.d(LOG_TAG, "MXOlmDevice : create a new olm account"); - // Else, create it - try { - mOlmAccount = new OlmAccount(); - mStore.storeAccount(mOlmAccount); - } catch (Exception e) { - Log.e(LOG_TAG, "MXOlmDevice : cannot initialize mOlmAccount " + e.getMessage(), e); - } - } else { - Log.d(LOG_TAG, "MXOlmDevice : use an existing account"); - } - - try { - mOlmUtility = new OlmUtility(); - } catch (Exception e) { - Log.e(LOG_TAG, "## MXOlmDevice : OlmUtility failed with error " + e.getMessage(), e); - mOlmUtility = null; - } - - mOutboundGroupSessionStore = new HashMap<>(); - - try { - mDeviceCurve25519Key = mOlmAccount.identityKeys().get(OlmAccount.JSON_KEY_IDENTITY_KEY); - } catch (Exception e) { - Log.e(LOG_TAG, "## MXOlmDevice : cannot find " + OlmAccount.JSON_KEY_IDENTITY_KEY + " with error " + e.getMessage(), e); - } - - try { - mDeviceEd25519Key = mOlmAccount.identityKeys().get(OlmAccount.JSON_KEY_FINGER_PRINT_KEY); - } catch (Exception e) { - Log.e(LOG_TAG, "## MXOlmDevice : cannot find " + OlmAccount.JSON_KEY_FINGER_PRINT_KEY + " with error " + e.getMessage(), e); - } - - mInboundGroupSessionMessageIndexes = new HashMap<>(); - } - - /** - * Release the instance - */ - public void release() { - if (null != mOlmAccount) { - mOlmAccount.releaseAccount(); - } - } - - /** - * @return the Curve25519 key for the account. - */ - public String getDeviceCurve25519Key() { - return mDeviceCurve25519Key; - } - - /** - * @return the Ed25519 key for the account. - */ - public String getDeviceEd25519Key() { - return mDeviceEd25519Key; - } - - /** - * Signs a message with the ed25519 key for this account. - * - * @param message the message to be signed. - * @return the base64-encoded signature. - */ - private String signMessage(String message) { - try { - return mOlmAccount.signMessage(message); - } catch (Exception e) { - Log.e(LOG_TAG, "## signMessage() : failed " + e.getMessage(), e); - } - - return null; - } - - /** - * Signs a JSON dictionary with the ed25519 key for this account. - * The signature is done on canonical version of the JSON. - * - * @param JSONDictionary the JSON to be signed. - * @return the base64-encoded signature - */ - public String signJSON(Map JSONDictionary) { - return signMessage(JsonUtils.getCanonicalizedJsonString(JSONDictionary)); - } - - /** - * @return The current (unused, unpublished) one-time keys for this account. - */ - public Map> getOneTimeKeys() { - try { - return mOlmAccount.oneTimeKeys(); - } catch (Exception e) { - Log.e(LOG_TAG, "## getOneTimeKeys() : failed " + e.getMessage(), e); - } - - return null; - } - - /** - * @return The maximum number of one-time keys the olm account can store. - */ - public long getMaxNumberOfOneTimeKeys() { - if (null != mOlmAccount) { - return mOlmAccount.maxOneTimeKeys(); - } else { - return -1; - } - } - - /** - * Marks all of the one-time keys as published. - */ - public void markKeysAsPublished() { - try { - mOlmAccount.markOneTimeKeysAsPublished(); - mStore.storeAccount(mOlmAccount); - } catch (Exception e) { - Log.e(LOG_TAG, "## markKeysAsPublished() : failed " + e.getMessage(), e); - } - } - - /** - * Generate some new one-time keys - * - * @param numKeys number of keys to generate - */ - public void generateOneTimeKeys(int numKeys) { - try { - mOlmAccount.generateOneTimeKeys(numKeys); - mStore.storeAccount(mOlmAccount); - } catch (Exception e) { - Log.e(LOG_TAG, "## generateOneTimeKeys() : failed " + e.getMessage(), e); - } - } - - /** - * Generate a new outbound session. - * The new session will be stored in the MXStore. - * - * @param theirIdentityKey the remote user's Curve25519 identity key - * @param theirOneTimeKey the remote user's one-time Curve25519 key - * @return the session id for the outbound session. @TODO OLMSession? - */ - public String createOutboundSession(String theirIdentityKey, String theirOneTimeKey) { - Log.d(LOG_TAG, "## createOutboundSession() ; theirIdentityKey " + theirIdentityKey + " theirOneTimeKey " + theirOneTimeKey); - OlmSession olmSession = null; - - try { - olmSession = new OlmSession(); - olmSession.initOutboundSession(mOlmAccount, theirIdentityKey, theirOneTimeKey); - mStore.storeSession(olmSession, theirIdentityKey); - - String sessionIdentifier = olmSession.sessionIdentifier(); - - Log.d(LOG_TAG, "## createOutboundSession() ; olmSession.sessionIdentifier: " + sessionIdentifier); - return sessionIdentifier; - - } catch (Exception e) { - Log.e(LOG_TAG, "## createOutboundSession() failed ; " + e.getMessage(), e); - - if (null != olmSession) { - olmSession.releaseSession(); - } - } - - return null; - } - - /** - * Generate a new inbound session, given an incoming message. - * - * @param theirDeviceIdentityKey the remote user's Curve25519 identity key. - * @param messageType the message_type field from the received message (must be 0). - * @param ciphertext base64-encoded body from the received message. - * @return {{payload: string, session_id: string}} decrypted payload, andsession id of new session. - */ - public Map createInboundSession(String theirDeviceIdentityKey, int messageType, String ciphertext) { - - Log.d(LOG_TAG, "## createInboundSession() : theirIdentityKey: " + theirDeviceIdentityKey); - - OlmSession olmSession = null; - - try { - try { - olmSession = new OlmSession(); - olmSession.initInboundSessionFrom(mOlmAccount, theirDeviceIdentityKey, ciphertext); - } catch (Exception e) { - Log.e(LOG_TAG, "## createInboundSession() : the session creation failed " + e.getMessage(), e); - return null; - } - - Log.d(LOG_TAG, "## createInboundSession() : sessionId: " + olmSession.sessionIdentifier()); - - try { - mOlmAccount.removeOneTimeKeys(olmSession); - mStore.storeAccount(mOlmAccount); - } catch (Exception e) { - Log.e(LOG_TAG, "## createInboundSession() : removeOneTimeKeys failed " + e.getMessage(), e); - } - - Log.d(LOG_TAG, "## createInboundSession() : ciphertext: " + ciphertext); - try { - Log.d(LOG_TAG, "## createInboundSession() :ciphertext: SHA256:" + mOlmUtility.sha256(URLEncoder.encode(ciphertext, "utf-8"))); - } catch (Exception e) { - Log.e(LOG_TAG, "## createInboundSession() :ciphertext: cannot encode ciphertext", e); - } - - OlmMessage olmMessage = new OlmMessage(); - olmMessage.mCipherText = ciphertext; - olmMessage.mType = messageType; - - String payloadString = null; - - try { - payloadString = olmSession.decryptMessage(olmMessage); - mStore.storeSession(olmSession, theirDeviceIdentityKey); - } catch (Exception e) { - Log.e(LOG_TAG, "## createInboundSession() : decryptMessage failed " + e.getMessage(), e); - } - - Map res = new HashMap<>(); - - if (!TextUtils.isEmpty(payloadString)) { - res.put("payload", payloadString); - } - - String sessionIdentifier = olmSession.sessionIdentifier(); - - if (!TextUtils.isEmpty(sessionIdentifier)) { - res.put("session_id", sessionIdentifier); - } - - return res; - } catch (Exception e) { - Log.e(LOG_TAG, "## createInboundSession() : OlmSession creation failed " + e.getMessage(), e); - - if (null != olmSession) { - olmSession.releaseSession(); - } - } - - return null; - } - - /** - * Get a list of known session IDs for the given device. - * - * @param theirDeviceIdentityKey the Curve25519 identity key for the remote device. - * @return a list of known session ids for the device. - */ - public Set getSessionIds(String theirDeviceIdentityKey) { - Map map = mStore.getDeviceSessions(theirDeviceIdentityKey); - - if (null != map) { - return map.keySet(); - } - - return null; - } - - /** - * Get the right olm session id for encrypting messages to the given identity key. - * - * @param theirDeviceIdentityKey the Curve25519 identity key for the remote device. - * @return the session id, or nil if no established session. - */ - public String getSessionId(String theirDeviceIdentityKey) { - String sessionId = null; - Set sessionIds = getSessionIds(theirDeviceIdentityKey); - - if ((null != sessionIds) && (0 != sessionIds.size())) { - List sessionIdsList = new ArrayList<>(sessionIds); - Collections.sort(sessionIdsList); - sessionId = sessionIdsList.get(0); - } - - return sessionId; - } - - /** - * Encrypt an outgoing message using an existing session. - * - * @param theirDeviceIdentityKey the Curve25519 identity key for the remote device. - * @param sessionId the id of the active session - * @param payloadString the payload to be encrypted and sent - * @return the cipher text - */ - public Map encryptMessage(String theirDeviceIdentityKey, String sessionId, String payloadString) { - Map res = null; - OlmMessage olmMessage; - OlmSession olmSession = getSessionForDevice(theirDeviceIdentityKey, sessionId); - - if (null != olmSession) { - try { - Log.d(LOG_TAG, "## encryptMessage() : olmSession.sessionIdentifier: " + olmSession.sessionIdentifier()); - //Log.d(LOG_TAG, "## encryptMessage() : payloadString: " + payloadString); - - olmMessage = olmSession.encryptMessage(payloadString); - mStore.storeSession(olmSession, theirDeviceIdentityKey); - res = new HashMap<>(); - - res.put("body", olmMessage.mCipherText); - res.put("type", olmMessage.mType); - } catch (Exception e) { - Log.e(LOG_TAG, "## encryptMessage() : failed " + e.getMessage(), e); - } - } - - return res; - } - - /** - * Decrypt an incoming message using an existing session. - * - * @param ciphertext the base64-encoded body from the received message. - * @param messageType message_type field from the received message. - * @param theirDeviceIdentityKey the Curve25519 identity key for the remote device. - * @param sessionId the id of the active session. - * @return the decrypted payload. - */ - public String decryptMessage(String ciphertext, int messageType, String sessionId, String theirDeviceIdentityKey) { - String payloadString = null; - - OlmSession olmSession = getSessionForDevice(theirDeviceIdentityKey, sessionId); - - if (null != olmSession) { - OlmMessage olmMessage = new OlmMessage(); - olmMessage.mCipherText = ciphertext; - olmMessage.mType = messageType; - - try { - payloadString = olmSession.decryptMessage(olmMessage); - mStore.storeSession(olmSession, theirDeviceIdentityKey); - } catch (Exception e) { - Log.e(LOG_TAG, "## decryptMessage() : decryptMessage failed " + e.getMessage(), e); - } - } - - return payloadString; - } - - /** - * Determine if an incoming messages is a prekey message matching an existing session. - * - * @param theirDeviceIdentityKey the Curve25519 identity key for the remote device. - * @param sessionId the id of the active session. - * @param messageType message_type field from the received message. - * @param ciphertext the base64-encoded body from the received message. - * @return YES if the received message is a prekey message which matchesthe given session. - */ - public boolean matchesSession(String theirDeviceIdentityKey, String sessionId, int messageType, String ciphertext) { - if (messageType != 0) { - return false; - } - - OlmSession olmSession = getSessionForDevice(theirDeviceIdentityKey, sessionId); - return (null != olmSession) && olmSession.matchesInboundSession(ciphertext); - } - - - // Outbound group session - - /** - * Generate a new outbound group session. - * - * @return the session id for the outbound session. - */ - public String createOutboundGroupSession() { - OlmOutboundGroupSession session = null; - try { - session = new OlmOutboundGroupSession(); - mOutboundGroupSessionStore.put(session.sessionIdentifier(), session); - return session.sessionIdentifier(); - } catch (Exception e) { - Log.e(LOG_TAG, "createOutboundGroupSession " + e.getMessage(), e); - - if (null != session) { - session.releaseSession(); - } - } - return null; - } - - /** - * Get the current session key of an outbound group session. - * - * @param sessionId the id of the outbound group session. - * @return the base64-encoded secret key. - */ - public String getSessionKey(String sessionId) { - if (!TextUtils.isEmpty(sessionId)) { - try { - return mOutboundGroupSessionStore.get(sessionId).sessionKey(); - } catch (Exception e) { - Log.e(LOG_TAG, "## getSessionKey() : failed " + e.getMessage(), e); - } - } - return null; - } - - /** - * Get the current message index of an outbound group session. - * - * @param sessionId the id of the outbound group session. - * @return the current chain index. - */ - public int getMessageIndex(String sessionId) { - if (!TextUtils.isEmpty(sessionId)) { - return mOutboundGroupSessionStore.get(sessionId).messageIndex(); - } - return 0; - } - - /** - * Encrypt an outgoing message with an outbound group session. - * - * @param sessionId the id of the outbound group session. - * @param payloadString the payload to be encrypted and sent. - * @return ciphertext - */ - public String encryptGroupMessage(String sessionId, String payloadString) { - if (!TextUtils.isEmpty(sessionId) && !TextUtils.isEmpty(payloadString)) { - try { - return mOutboundGroupSessionStore.get(sessionId).encryptMessage(payloadString); - } catch (Exception e) { - Log.e(LOG_TAG, "## encryptGroupMessage() : failed " + e.getMessage(), e); - } - } - return null; - } - - // Inbound group session - - /** - * Add an inbound group session to the session store. - * - * @param sessionId the session identifier. - * @param sessionKey base64-encoded secret key. - * @param roomId the id of the room in which this session will be used. - * @param senderKey the base64-encoded curve25519 key of the sender. - * @param forwardingCurve25519KeyChain Devices involved in forwarding this session to us. - * @param keysClaimed Other keys the sender claims. - * @param exportFormat true if the megolm keys are in export format - * @return true if the operation succeeds. - */ - public boolean addInboundGroupSession(String sessionId, - String sessionKey, - String roomId, - String senderKey, - List forwardingCurve25519KeyChain, - Map keysClaimed, - boolean exportFormat) { - if (null != getInboundGroupSession(sessionId, senderKey, roomId)) { - // If we already have this session, consider updating it - Log.e(LOG_TAG, "## addInboundGroupSession() : Update for megolm session " + senderKey + "/" + sessionId); - - // For now we just ignore updates. TODO: implement something here - return false; - } - - MXOlmInboundGroupSession2 session = new MXOlmInboundGroupSession2(sessionKey, exportFormat); - - // sanity check - if (null == session.mSession) { - Log.e(LOG_TAG, "## addInboundGroupSession : invalid session"); - return false; - } - - try { - if (!TextUtils.equals(session.mSession.sessionIdentifier(), sessionId)) { - Log.e(LOG_TAG, "## addInboundGroupSession : ERROR: Mismatched group session ID from senderKey: " + senderKey); - return false; - } - } catch (Exception e) { - Log.e(LOG_TAG, "## addInboundGroupSession : sessionIdentifier') failed " + e.getMessage(), e); - return false; - } - - session.mSenderKey = senderKey; - session.mRoomId = roomId; - session.mKeysClaimed = keysClaimed; - session.mForwardingCurve25519KeyChain = forwardingCurve25519KeyChain; - - mStore.storeInboundGroupSession(session); - - return true; - } - - /** - * Import an inbound group session to the session store. - * - * @param exportedSessionMap the exported session map - * @return the imported session if the operation succeeds. - */ - public MXOlmInboundGroupSession2 importInboundGroupSession(Map exportedSessionMap) { - String sessionId = (String) exportedSessionMap.get("session_id"); - String senderKey = (String) exportedSessionMap.get("sender_key"); - String roomId = (String) exportedSessionMap.get("room_id"); - - if (null != getInboundGroupSession(sessionId, senderKey, roomId)) { - // If we already have this session, consider updating it - Log.e(LOG_TAG, "## importInboundGroupSession() : Update for megolm session " + senderKey + "/" + sessionId); - - // For now we just ignore updates. TODO: implement something here - return null; - } - - MXOlmInboundGroupSession2 session = null; - - try { - session = new MXOlmInboundGroupSession2(exportedSessionMap); - } catch (Exception e) { - Log.e(LOG_TAG, "## importInboundGroupSession() : Update for megolm session " + senderKey + "/" + sessionId, e); - } - - // sanity check - if ((null == session) || (null == session.mSession)) { - Log.e(LOG_TAG, "## importInboundGroupSession : invalid session"); - return null; - } - - try { - if (!TextUtils.equals(session.mSession.sessionIdentifier(), sessionId)) { - Log.e(LOG_TAG, "## importInboundGroupSession : ERROR: Mismatched group session ID from senderKey: " + senderKey); - return null; - } - } catch (Exception e) { - Log.e(LOG_TAG, "## importInboundGroupSession : sessionIdentifier') failed " + e.getMessage(), e); - return null; - } - - mStore.storeInboundGroupSession(session); - - return session; - } - - /** - * Remove an inbound group session - * - * @param sessionId the session identifier. - * @param sessionKey base64-encoded secret key. - */ - public void removeInboundGroupSession(String sessionId, String sessionKey) { - if ((null != sessionId) && (null != sessionKey)) { - mStore.removeInboundGroupSession(sessionId, sessionKey); - } - } - - /** - * Decrypt a received message with an inbound group session. - * - * @param body the base64-encoded body of the encrypted message. - * @param roomId theroom in which the message was received. - * @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack. - * @param sessionId the session identifier. - * @param senderKey the base64-encoded curve25519 key of the sender. - * @return the decrypting result. Nil if the sessionId is unknown. - */ - public MXDecryptionResult decryptGroupMessage(String body, - String roomId, - String timeline, - String sessionId, - String senderKey) throws MXDecryptionException { - MXDecryptionResult result = new MXDecryptionResult(); - MXOlmInboundGroupSession2 session = getInboundGroupSession(sessionId, senderKey, roomId); - - if (null != session) { - // Check that the room id matches the original one for the session. This stops - // the HS pretending a message was targeting a different room. - if (TextUtils.equals(roomId, session.mRoomId)) { - String errorMessage = ""; - OlmInboundGroupSession.DecryptMessageResult decryptResult = null; - try { - decryptResult = session.mSession.decryptMessage(body); - } catch (Exception e) { - Log.e(LOG_TAG, "## decryptGroupMessage () : decryptMessage failed " + e.getMessage(), e); - errorMessage = e.getMessage(); - } - - if (null != decryptResult) { - if (null != timeline) { - if (!mInboundGroupSessionMessageIndexes.containsKey(timeline)) { - mInboundGroupSessionMessageIndexes.put(timeline, new HashMap()); - } - - String messageIndexKey = senderKey + "|" + sessionId + "|" + decryptResult.mIndex; - - if (null != mInboundGroupSessionMessageIndexes.get(timeline).get(messageIndexKey)) { - String reason = String.format(MXCryptoError.DUPLICATE_MESSAGE_INDEX_REASON, decryptResult.mIndex); - Log.e(LOG_TAG, "## decryptGroupMessage() : " + reason); - throw new MXDecryptionException(new MXCryptoError(MXCryptoError.DUPLICATED_MESSAGE_INDEX_ERROR_CODE, - MXCryptoError.UNABLE_TO_DECRYPT, reason)); - } - - mInboundGroupSessionMessageIndexes.get(timeline).put(messageIndexKey, true); - } - - mStore.storeInboundGroupSession(session); - try { - JsonParser parser = new JsonParser(); - result.mPayload = parser.parse(JsonUtils.convertFromUTF8(decryptResult.mDecryptedMessage)); - } catch (Exception e) { - Log.e(LOG_TAG, "## decryptGroupMessage() : RLEncoder.encode failed " + e.getMessage(), e); - return null; - } - - if (null == result.mPayload) { - Log.e(LOG_TAG, "## decryptGroupMessage() : fails to parse the payload"); - return null; - } - - result.mKeysClaimed = session.mKeysClaimed; - result.mSenderKey = senderKey; - result.mForwardingCurve25519KeyChain = session.mForwardingCurve25519KeyChain; - } else { - Log.e(LOG_TAG, "## decryptGroupMessage() : failed to decode the message"); - throw new MXDecryptionException(new MXCryptoError(MXCryptoError.OLM_ERROR_CODE, errorMessage, null)); - } - } else { - String reason = String.format(MXCryptoError.INBOUND_SESSION_MISMATCH_ROOM_ID_REASON, roomId, session.mRoomId); - Log.e(LOG_TAG, "## decryptGroupMessage() : " + reason); - throw new MXDecryptionException(new MXCryptoError(MXCryptoError.INBOUND_SESSION_MISMATCH_ROOM_ID_ERROR_CODE, - MXCryptoError.UNABLE_TO_DECRYPT, reason)); - } - } else { - Log.e(LOG_TAG, "## decryptGroupMessage() : Cannot retrieve inbound group session " + sessionId); - throw new MXDecryptionException(mInboundGroupSessionWithIdError); - } - - return result; - } - - /** - * Reset replay attack data for the given timeline. - * - * @param timeline the id of the timeline. - */ - public void resetReplayAttackCheckInTimeline(String timeline) { - if (null != timeline) { - mInboundGroupSessionMessageIndexes.remove(timeline); - } - } - - // Utilities - - /** - * Verify an ed25519 signature on a JSON object. - * - * @param key the ed25519 key. - * @param JSONDictinary the JSON object which was signed. - * @param signature the base64-encoded signature to be checked. - * @throws Exception the exception - */ - public void verifySignature(String key, Map JSONDictinary, String signature) throws Exception { - // Check signature on the canonical version of the JSON - mOlmUtility.verifyEd25519Signature(signature, key, JsonUtils.getCanonicalizedJsonString(JSONDictinary)); - } - - /** - * Calculate the SHA-256 hash of the input and encodes it as base64. - * - * @param message the message to hash. - * @return the base64-encoded hash value. - */ - public String sha256(String message) { - return mOlmUtility.sha256(JsonUtils.convertToUTF8(message)); - } - - /** - * Search an OlmSession - * - * @param theirDeviceIdentityKey the device key - * @param sessionId the session Id - * @return the olm session - */ - private OlmSession getSessionForDevice(String theirDeviceIdentityKey, String sessionId) { - // sanity check - if (!TextUtils.isEmpty(theirDeviceIdentityKey) && !TextUtils.isEmpty(sessionId)) { - Map map = mStore.getDeviceSessions(theirDeviceIdentityKey); - - if (null != map) { - return map.get(sessionId); - } - } - - return null; - } - - /** - * Extract an InboundGroupSession from the session store and do some check. - * mInboundGroupSessionWithIdError describes the failure reason. - * - * @param roomId the room where the sesion is used. - * @param sessionId the session identifier. - * @param senderKey the base64-encoded curve25519 key of the sender. - * @return the inbound group session. - */ - public MXOlmInboundGroupSession2 getInboundGroupSession(String sessionId, String senderKey, String roomId) { - mInboundGroupSessionWithIdError = null; - - MXOlmInboundGroupSession2 session = mStore.getInboundGroupSession(sessionId, senderKey); - - if (null != session) { - // Check that the room id matches the original one for the session. This stops - // the HS pretending a message was targeting a different room. - if (!TextUtils.equals(roomId, session.mRoomId)) { - String errorDescription = String.format(MXCryptoError.INBOUND_SESSION_MISMATCH_ROOM_ID_REASON, roomId, session.mRoomId); - Log.e(LOG_TAG, "## getInboundGroupSession() : " + errorDescription); - mInboundGroupSessionWithIdError = new MXCryptoError(MXCryptoError.INBOUND_SESSION_MISMATCH_ROOM_ID_ERROR_CODE, - MXCryptoError.UNABLE_TO_DECRYPT, errorDescription); - } - } else { - Log.e(LOG_TAG, "## getInboundGroupSession() : Cannot retrieve inbound group session " + sessionId); - mInboundGroupSessionWithIdError = new MXCryptoError(MXCryptoError.UNKNOWN_INBOUND_SESSION_ID_ERROR_CODE, - MXCryptoError.UNKNOWN_INBOUND_SESSION_ID_REASON, null); - } - return session; - } - - /** - * Determine if we have the keys for a given megolm session. - * - * @param roomId room in which the message was received - * @param senderKey base64-encoded curve25519 key of the sender - * @param sessionId session identifier - * @return true if the unbound session keys are known. - */ - public boolean hasInboundSessionKeys(String roomId, String senderKey, String sessionId) { - return null != getInboundGroupSession(sessionId, senderKey, roomId); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXOutgoingRoomKeyRequestManager.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXOutgoingRoomKeyRequestManager.java deleted file mode 100755 index f3f1dc1d..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/MXOutgoingRoomKeyRequestManager.java +++ /dev/null @@ -1,371 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.crypto; - -import android.os.Handler; - -import im.vector.matrix.android.internal.legacy.MXSession; -import im.vector.matrix.android.internal.legacy.crypto.data.MXUsersDevicesMap; -import im.vector.matrix.android.internal.legacy.data.cryptostore.IMXCryptoStore; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.RoomKeyRequest; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; - -public class MXOutgoingRoomKeyRequestManager { - private static final String LOG_TAG = MXOutgoingRoomKeyRequestManager.class.getSimpleName(); - - private static final int SEND_KEY_REQUESTS_DELAY_MS = 500; - - // the linked session - private MXSession mSession; - - // working handler (should not be the UI thread) - private Handler mWorkingHandler; - - // store - private IMXCryptoStore mCryptoStore; - - // running - public boolean mClientRunning; - - // transaction counter - private int mTxnCtr; - - // sanity check to ensure that we don't end up with two concurrent runs - // of mSendOutgoingRoomKeyRequestsTimer - private boolean mSendOutgoingRoomKeyRequestsRunning; - - /** - * Constructor - * - * @param session the session - * @param crypto the crypto engine - */ - public MXOutgoingRoomKeyRequestManager(MXSession session, MXCrypto crypto) { - mSession = session; - mWorkingHandler = crypto.getEncryptingThreadHandler(); - mCryptoStore = crypto.getCryptoStore(); - } - - /** - * Called when the client is started. Sets background processes running. - */ - public void start() { - mClientRunning = true; - startTimer(); - } - - /** - * Called when the client is stopped. Stops any running background processes. - */ - public void stop() { - mClientRunning = false; - } - - /** - * Make up a new transaction id - * - * @return {string} a new, unique, transaction id - */ - private String makeTxnId() { - return "m" + System.currentTimeMillis() + "." + mTxnCtr++; - } - - /** - * Send off a room key request, if we haven't already done so. - *

- * The `requestBody` is compared (with a deep-equality check) against - * previous queued or sent requests and if it matches, no change is made. - * Otherwise, a request is added to the pending list, and a job is started - * in the background to send it. - * - * @param requestBody requestBody - * @param recipients recipients - */ - public void sendRoomKeyRequest(final Map requestBody, final List> recipients) { - mWorkingHandler.post(new Runnable() { - @Override - public void run() { - OutgoingRoomKeyRequest req = mCryptoStore.getOrAddOutgoingRoomKeyRequest( - new OutgoingRoomKeyRequest(requestBody, recipients, makeTxnId(), OutgoingRoomKeyRequest.RequestState.UNSENT)); - - - if (req.mState == OutgoingRoomKeyRequest.RequestState.UNSENT) { - startTimer(); - } - } - }); - } - - /** - * Cancel room key requests, if any match the given details - * - * @param requestBody requestBody - */ - public void cancelRoomKeyRequest(final Map requestBody) { - cancelRoomKeyRequest(requestBody, false); - } - - /** - * Cancel room key requests, if any match the given details, and resend - * - * @param requestBody requestBody - */ - public void resendRoomKeyRequest(final Map requestBody) { - cancelRoomKeyRequest(requestBody, true); - } - - /** - * Cancel room key requests, if any match the given details, and resend - * - * @param requestBody requestBody - * @param andResend true to resend the key request - */ - private void cancelRoomKeyRequest(final Map requestBody, boolean andResend) { - OutgoingRoomKeyRequest req = mCryptoStore.getOutgoingRoomKeyRequest(requestBody); - - if (null == req) { - // no request was made for this key - return; - } - - if (req.mState == OutgoingRoomKeyRequest.RequestState.CANCELLATION_PENDING - || req.mState == OutgoingRoomKeyRequest.RequestState.CANCELLATION_PENDING_AND_WILL_RESEND) { - // nothing to do here - } else if ((req.mState == OutgoingRoomKeyRequest.RequestState.UNSENT) - || (req.mState == OutgoingRoomKeyRequest.RequestState.FAILED)) { - Log.d(LOG_TAG, "## cancelRoomKeyRequest() : deleting unnecessary room key request for " + requestBody); - mCryptoStore.deleteOutgoingRoomKeyRequest(req.mRequestId); - } else if (req.mState == OutgoingRoomKeyRequest.RequestState.SENT) { - if (andResend) { - req.mState = OutgoingRoomKeyRequest.RequestState.CANCELLATION_PENDING_AND_WILL_RESEND; - } else { - req.mState = OutgoingRoomKeyRequest.RequestState.CANCELLATION_PENDING; - } - req.mCancellationTxnId = makeTxnId(); - mCryptoStore.updateOutgoingRoomKeyRequest(req); - sendOutgoingRoomKeyRequestCancellation(req); - } - } - - - /** - * Start the background timer to send queued requests, if the timer isn't already running. - */ - private void startTimer() { - mWorkingHandler.post(new Runnable() { - @Override - public void run() { - if (mSendOutgoingRoomKeyRequestsRunning) { - return; - } - - mWorkingHandler.postDelayed(new Runnable() { - @Override - public void run() { - if (mSendOutgoingRoomKeyRequestsRunning) { - Log.d(LOG_TAG, "## startTimer() : RoomKeyRequestSend already in progress!"); - return; - } - - mSendOutgoingRoomKeyRequestsRunning = true; - sendOutgoingRoomKeyRequests(); - } - }, SEND_KEY_REQUESTS_DELAY_MS); - } - }); - } - - // look for and send any queued requests. Runs itself recursively until - // there are no more requests, or there is an error (in which case, the - // timer will be restarted before the promise resolves). - private void sendOutgoingRoomKeyRequests() { - if (!mClientRunning) { - mSendOutgoingRoomKeyRequestsRunning = false; - return; - } - - Log.d(LOG_TAG, "## sendOutgoingRoomKeyRequests() : Looking for queued outgoing room key requests"); - OutgoingRoomKeyRequest outgoingRoomKeyRequest = mCryptoStore.getOutgoingRoomKeyRequestByState( - new HashSet<>(Arrays.asList(OutgoingRoomKeyRequest.RequestState.UNSENT, - OutgoingRoomKeyRequest.RequestState.CANCELLATION_PENDING, - OutgoingRoomKeyRequest.RequestState.CANCELLATION_PENDING_AND_WILL_RESEND))); - - if (null == outgoingRoomKeyRequest) { - Log.e(LOG_TAG, "## sendOutgoingRoomKeyRequests() : No more outgoing room key requests"); - mSendOutgoingRoomKeyRequestsRunning = false; - return; - } - - if (OutgoingRoomKeyRequest.RequestState.UNSENT == outgoingRoomKeyRequest.mState) { - sendOutgoingRoomKeyRequest(outgoingRoomKeyRequest); - } else { - sendOutgoingRoomKeyRequestCancellation(outgoingRoomKeyRequest); - } - } - - /** - * Send the outgoing key request. - * - * @param request the request - */ - private void sendOutgoingRoomKeyRequest(final OutgoingRoomKeyRequest request) { - Log.d(LOG_TAG, "## sendOutgoingRoomKeyRequest() : Requesting keys " + request.mRequestBody - + " from " + request.mRecipients + " id " + request.mRequestId); - - Map requestMessage = new HashMap<>(); - requestMessage.put("action", "request"); - requestMessage.put("requesting_device_id", mCryptoStore.getDeviceId()); - requestMessage.put("request_id", request.mRequestId); - requestMessage.put("body", request.mRequestBody); - - sendMessageToDevices(requestMessage, request.mRecipients, request.mRequestId, new ApiCallback() { - private void onDone(final OutgoingRoomKeyRequest.RequestState state) { - mWorkingHandler.post(new Runnable() { - @Override - public void run() { - if (request.mState != OutgoingRoomKeyRequest.RequestState.UNSENT) { - Log.d(LOG_TAG, "## sendOutgoingRoomKeyRequest() : Cannot update room key request from UNSENT as it was already updated to " - + request.mState); - } else { - request.mState = state; - mCryptoStore.updateOutgoingRoomKeyRequest(request); - } - - mSendOutgoingRoomKeyRequestsRunning = false; - startTimer(); - } - }); - } - - @Override - public void onSuccess(Void info) { - Log.d(LOG_TAG, "## sendOutgoingRoomKeyRequest succeed"); - onDone(OutgoingRoomKeyRequest.RequestState.SENT); - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "## sendOutgoingRoomKeyRequest failed " + e.getMessage(), e); - onDone(OutgoingRoomKeyRequest.RequestState.FAILED); - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "## sendOutgoingRoomKeyRequest failed " + e.getMessage()); - onDone(OutgoingRoomKeyRequest.RequestState.FAILED); - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "## sendOutgoingRoomKeyRequest failed " + e.getMessage(), e); - onDone(OutgoingRoomKeyRequest.RequestState.FAILED); - } - }); - } - - /** - * Given a RoomKeyRequest, cancel it and delete the request record - * - * @param request the request - */ - private void sendOutgoingRoomKeyRequestCancellation(final OutgoingRoomKeyRequest request) { - Log.d(LOG_TAG, "## sendOutgoingRoomKeyRequestCancellation() : Sending cancellation for key request for " + request.mRequestBody - + " to " + request.mRecipients - + " cancellation id " + request.mCancellationTxnId); - - Map requestMessageMap = new HashMap<>(); - requestMessageMap.put("action", RoomKeyRequest.ACTION_REQUEST_CANCELLATION); - requestMessageMap.put("requesting_device_id", mCryptoStore.getDeviceId()); - requestMessageMap.put("request_id", request.mCancellationTxnId); - - sendMessageToDevices(requestMessageMap, request.mRecipients, request.mCancellationTxnId, new ApiCallback() { - private void onDone() { - mWorkingHandler.post(new Runnable() { - @Override - public void run() { - mCryptoStore.deleteOutgoingRoomKeyRequest(request.mRequestId); - mSendOutgoingRoomKeyRequestsRunning = false; - startTimer(); - } - }); - } - - - @Override - public void onSuccess(Void info) { - Log.d(LOG_TAG, "## sendOutgoingRoomKeyRequestCancellation() : done"); - boolean resend = request.mState == OutgoingRoomKeyRequest.RequestState.CANCELLATION_PENDING_AND_WILL_RESEND; - - onDone(); - - // Resend the request with a new ID - if (resend) { - sendRoomKeyRequest(request.mRequestBody, request.mRecipients); - } - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "## sendOutgoingRoomKeyRequestCancellation failed " + e.getMessage(), e); - onDone(); - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "## sendOutgoingRoomKeyRequestCancellation failed " + e.getMessage()); - onDone(); - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "## sendOutgoingRoomKeyRequestCancellation failed " + e.getMessage(), e); - onDone(); - } - }); - } - - /** - * Send a RoomKeyRequest to a list of recipients - * - * @param message the message - * @param recipients the recipients. - * @param transactionId the transaction id - * @param callback the asynchronous callback. - */ - private void sendMessageToDevices(final Map message, - List> recipients, - String transactionId, - final ApiCallback callback) { - MXUsersDevicesMap> contentMap = new MXUsersDevicesMap<>(); - - for (Map recipient : recipients) { - contentMap.setObject(message, recipient.get("userId"), recipient.get("deviceId")); - } - - mSession.getCryptoRestClient().sendToDevice(Event.EVENT_TYPE_ROOM_KEY_REQUEST, contentMap, transactionId, callback); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/OutgoingRoomKeyRequest.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/OutgoingRoomKeyRequest.java deleted file mode 100755 index 5e9ba695..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/OutgoingRoomKeyRequest.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.crypto; - -import java.io.Serializable; -import java.util.List; -import java.util.Map; - -/** - * Represents an outgoing room key request - */ -public class OutgoingRoomKeyRequest implements Serializable { - - /** - * possible states for a room key request - * - * The state machine looks like: - * - * | - * V - * UNSENT -----------------------------+ - * | | - * | (send successful) | (cancellation requested) - * V | - * SENT | - * |-------------------------------- | --------------+ - * | | | - * | | | (cancellation requested with intent - * | | | to resend a new request) - * | (cancellation requested) | | - * V | V - * CANCELLATION_PENDING | CANCELLATION_PENDING_AND_WILL_RESEND - * | | | - * | (cancellation sent) | | (cancellation sent. Create new request - * | | | in the UNSENT state) - * V | | - * (deleted) <---------------------------+----------------+ - */ - - public enum RequestState { - /** - * request not yet sent - */ - UNSENT, - /** - * request sent, awaiting reply - */ - SENT, - /** - * reply received, cancellation not yet sent - */ - CANCELLATION_PENDING, - /** - * Cancellation not yet sent, once sent, a new request will be done - */ - CANCELLATION_PENDING_AND_WILL_RESEND, - /** - * sending failed - */ - FAILED - } - - // Unique id for this request. Used for both - // an id within the request for later pairing with a cancellation, and for - // the transaction id when sending the to_device messages to our local - public String mRequestId; - - // transaction id for the cancellation, if any - public String mCancellationTxnId; - - // list of recipients for the request - public List> mRecipients; - - // RequestBody - public Map mRequestBody; - - // current state of this request - public RequestState mState; - - public OutgoingRoomKeyRequest(Map requestBody, List> recipients, String requestId, RequestState state) { - mRequestBody = requestBody; - mRecipients = recipients; - mRequestId = requestId; - mState = state; - } - - /** - * @return the room id - */ - public String getRoomId() { - if (null != mRequestBody) { - return mRequestBody.get("room_id"); - } - - return null; - } - - /** - * @return the session id - */ - public String getSessionId() { - if (null != mRequestBody) { - return mRequestBody.get("session_id"); - } - - return null; - } -} - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/IMXDecrypting.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/IMXDecrypting.java deleted file mode 100644 index 958b0d6f..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/IMXDecrypting.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2015 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.crypto.algorithms; - -import android.support.annotation.Nullable; - -import im.vector.matrix.android.internal.legacy.MXSession; -import im.vector.matrix.android.internal.legacy.crypto.IncomingRoomKeyRequest; -import im.vector.matrix.android.internal.legacy.crypto.MXDecryptionException; -import im.vector.matrix.android.internal.legacy.crypto.MXEventDecryptionResult; -import im.vector.matrix.android.internal.legacy.rest.model.Event; - -/** - * An interface for decrypting data - */ -public interface IMXDecrypting { - /** - * Init the object fields - * - * @param matrixSession the session - */ - void initWithMatrixSession(MXSession matrixSession); - - /** - * Decrypt an event - * - * @param event the raw event. - * @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack. - * @return the decryption information, or null in case of error - * @throws MXDecryptionException the decryption failure reason - */ - @Nullable - MXEventDecryptionResult decryptEvent(Event event, String timeline) throws MXDecryptionException; - - /** - * Handle a key event. - * - * @param event the key event. - */ - void onRoomKeyEvent(Event event); - - /** - * Check if the some messages can be decrypted with a new session - * - * @param senderKey the session sender key - * @param sessionId the session id - */ - void onNewSession(String senderKey, String sessionId); - - /** - * Determine if we have the keys necessary to respond to a room key request - * - * @param request keyRequest - * @return true if we have the keys and could (theoretically) share - */ - boolean hasKeysForKeyRequest(IncomingRoomKeyRequest request); - - /** - * Send the response to a room key request. - * - * @param request keyRequest - */ - void shareKeysWithDevice(IncomingRoomKeyRequest request); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/IMXEncrypting.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/IMXEncrypting.java deleted file mode 100644 index 3765b4f5..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/IMXEncrypting.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2015 OpenMarket Ltd - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.crypto.algorithms; - -import com.google.gson.JsonElement; - -import im.vector.matrix.android.internal.legacy.MXSession; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; - -import java.util.List; - -/** - * An interface for encrypting data - */ -public interface IMXEncrypting { - - /** - * Init - * - * @param matrixSession the related 'MXSession'. - * @param roomId the id of the room we will be sending to. - */ - void initWithMatrixSession(MXSession matrixSession, String roomId); - - /** - * Encrypt an event content according to the configuration of the room. - * - * @param eventContent the content of the event. - * @param eventType the type of the event. - * @param userIds the room members the event will be sent to. - * @param callback the asynchronous callback - */ - void encryptEventContent(JsonElement eventContent, String eventType, List userIds, ApiCallback callback); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/MXDecryptionResult.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/MXDecryptionResult.java deleted file mode 100755 index e5842760..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/MXDecryptionResult.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.crypto.algorithms; - -import com.google.gson.JsonElement; - -import java.util.List; -import java.util.Map; - -/** - * This class represents the decryption result. - */ -public class MXDecryptionResult { - /** - * The decrypted payload (with properties 'type', 'content') - */ - public JsonElement mPayload; - - /** - * keys that the sender of the event claims ownership of: - * map from key type to base64-encoded key. - */ - public Map mKeysClaimed; - - /** - * The curve25519 key that the sender of the event is known to have ownership of. - */ - public String mSenderKey; - - /** - * Devices which forwarded this session to us (normally empty). - */ - public List mForwardingCurve25519KeyChain; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/megolm/MXMegolmDecryption.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/megolm/MXMegolmDecryption.java deleted file mode 100644 index 12f3e1d2..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/megolm/MXMegolmDecryption.java +++ /dev/null @@ -1,468 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.crypto.algorithms.megolm; - -import android.support.annotation.Nullable; -import android.text.TextUtils; - -import im.vector.matrix.android.internal.legacy.MXSession; -import im.vector.matrix.android.internal.legacy.crypto.IncomingRoomKeyRequest; -import im.vector.matrix.android.internal.legacy.crypto.MXCryptoError; -import im.vector.matrix.android.internal.legacy.crypto.MXDecryptionException; -import im.vector.matrix.android.internal.legacy.crypto.MXEventDecryptionResult; -import im.vector.matrix.android.internal.legacy.crypto.MXOlmDevice; -import im.vector.matrix.android.internal.legacy.crypto.algorithms.IMXDecrypting; -import im.vector.matrix.android.internal.legacy.crypto.algorithms.MXDecryptionResult; -import im.vector.matrix.android.internal.legacy.crypto.data.MXDeviceInfo; -import im.vector.matrix.android.internal.legacy.crypto.data.MXOlmInboundGroupSession2; -import im.vector.matrix.android.internal.legacy.crypto.data.MXOlmSessionResult; -import im.vector.matrix.android.internal.legacy.crypto.data.MXUsersDevicesMap; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.EncryptedEventContent; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.ForwardedRoomKeyContent; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.RoomKeyContent; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.RoomKeyRequestBody; -import im.vector.matrix.android.internal.legacy.util.JsonUtils; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -public class MXMegolmDecryption implements IMXDecrypting { - private static final String LOG_TAG = MXMegolmDecryption.class.getSimpleName(); - - /** - * The olm device interface - */ - private MXOlmDevice mOlmDevice; - - // the matrix session - private MXSession mSession; - - /** - * Events which we couldn't decrypt due to unknown sessions / indexes: map from - * senderKey|sessionId to timelines to list of MatrixEvents. - */ - private Map>> mPendingEvents; - - /** - * Init the object fields - * - * @param matrixSession the matrix session - */ - @Override - public void initWithMatrixSession(MXSession matrixSession) { - mSession = matrixSession; - mOlmDevice = matrixSession.getCrypto().getOlmDevice(); - mPendingEvents = new HashMap<>(); - - } - - @Override - @Nullable - public MXEventDecryptionResult decryptEvent(Event event, String timeline) throws MXDecryptionException { - return decryptEvent(event, timeline, true); - } - - @Nullable - private MXEventDecryptionResult decryptEvent(Event event, String timeline, boolean requestKeysOnFail) throws MXDecryptionException { - // sanity check - if (null == event) { - Log.e(LOG_TAG, "## decryptEvent() : null event"); - return null; - } - - EncryptedEventContent encryptedEventContent = JsonUtils.toEncryptedEventContent(event.getWireContent().getAsJsonObject()); - - String senderKey = encryptedEventContent.sender_key; - String ciphertext = encryptedEventContent.ciphertext; - String sessionId = encryptedEventContent.session_id; - - if (TextUtils.isEmpty(senderKey) || TextUtils.isEmpty(sessionId) || TextUtils.isEmpty(ciphertext)) { - throw new MXDecryptionException(new MXCryptoError(MXCryptoError.MISSING_FIELDS_ERROR_CODE, - MXCryptoError.UNABLE_TO_DECRYPT, MXCryptoError.MISSING_FIELDS_REASON)); - } - - MXEventDecryptionResult eventDecryptionResult = null; - MXCryptoError cryptoError = null; - MXDecryptionResult decryptGroupMessageResult = null; - - try { - decryptGroupMessageResult = mOlmDevice.decryptGroupMessage(ciphertext, event.roomId, timeline, sessionId, senderKey); - } catch (MXDecryptionException e) { - cryptoError = e.getCryptoError(); - } - - // the decryption succeeds - if ((null != decryptGroupMessageResult) && (null != decryptGroupMessageResult.mPayload) && (null == cryptoError)) { - eventDecryptionResult = new MXEventDecryptionResult(); - - eventDecryptionResult.mClearEvent = decryptGroupMessageResult.mPayload; - eventDecryptionResult.mSenderCurve25519Key = decryptGroupMessageResult.mSenderKey; - - if (null != decryptGroupMessageResult.mKeysClaimed) { - eventDecryptionResult.mClaimedEd25519Key = decryptGroupMessageResult.mKeysClaimed.get("ed25519"); - } - - eventDecryptionResult.mForwardingCurve25519KeyChain = decryptGroupMessageResult.mForwardingCurve25519KeyChain; - } else if (null != cryptoError) { - if (cryptoError.isOlmError()) { - if (TextUtils.equals("UNKNOWN_MESSAGE_INDEX", cryptoError.error)) { - addEventToPendingList(event, timeline); - - if (requestKeysOnFail) { - requestKeysForEvent(event); - } - } - - String reason = String.format(MXCryptoError.OLM_REASON, cryptoError.error); - String detailedReason = String.format(MXCryptoError.DETAILLED_OLM_REASON, ciphertext, cryptoError.error); - - throw new MXDecryptionException(new MXCryptoError( - MXCryptoError.OLM_ERROR_CODE, - reason, - detailedReason)); - } else if (TextUtils.equals(cryptoError.errcode, MXCryptoError.UNKNOWN_INBOUND_SESSION_ID_ERROR_CODE)) { - addEventToPendingList(event, timeline); - if (requestKeysOnFail) { - requestKeysForEvent(event); - } - } - - throw new MXDecryptionException(cryptoError); - } - - return eventDecryptionResult; - } - - /** - * Helper for the real decryptEvent and for _retryDecryption. If - * requestKeysOnFail is true, we'll send an m.room_key_request when we fail - * to decrypt the event due to missing megolm keys. - * - * @param event the event - */ - private void requestKeysForEvent(Event event) { - String sender = event.getSender(); - EncryptedEventContent wireContent = JsonUtils.toEncryptedEventContent(event.getWireContent()); - - List> recipients = new ArrayList<>(); - - Map selfMap = new HashMap<>(); - selfMap.put("userId", mSession.getMyUserId()); - selfMap.put("deviceId", "*"); - recipients.add(selfMap); - - if (!TextUtils.equals(sender, mSession.getMyUserId())) { - Map senderMap = new HashMap<>(); - senderMap.put("userId", sender); - senderMap.put("deviceId", wireContent.device_id); - recipients.add(senderMap); - } - - Map requestBody = new HashMap<>(); - requestBody.put("room_id", event.roomId); - requestBody.put("algorithm", wireContent.algorithm); - requestBody.put("sender_key", wireContent.sender_key); - requestBody.put("session_id", wireContent.session_id); - - mSession.getCrypto().requestRoomKey(requestBody, recipients); - } - - /** - * Add an event to the list of those we couldn't decrypt the first time we - * saw them. - * - * @param event the event to try to decrypt later - * @param timelineId the timeline identifier - */ - private void addEventToPendingList(Event event, String timelineId) { - EncryptedEventContent encryptedEventContent = JsonUtils.toEncryptedEventContent(event.getWireContent().getAsJsonObject()); - - String senderKey = encryptedEventContent.sender_key; - String sessionId = encryptedEventContent.session_id; - - String k = senderKey + "|" + sessionId; - - // avoid undefined timelineId - if (TextUtils.isEmpty(timelineId)) { - timelineId = ""; - } - - if (!mPendingEvents.containsKey(k)) { - mPendingEvents.put(k, new HashMap>()); - } - - if (!mPendingEvents.get(k).containsKey(timelineId)) { - mPendingEvents.get(k).put(timelineId, new ArrayList()); - } - - if (mPendingEvents.get(k).get(timelineId).indexOf(event) < 0) { - Log.d(LOG_TAG, "## addEventToPendingList() : add Event " + event.eventId + " in room id " + event.roomId); - mPendingEvents.get(k).get(timelineId).add(event); - } - } - - /** - * Handle a key event. - * - * @param roomKeyEvent the key event. - */ - @Override - public void onRoomKeyEvent(Event roomKeyEvent) { - boolean exportFormat = false; - RoomKeyContent roomKeyContent = JsonUtils.toRoomKeyContent(roomKeyEvent.getContentAsJsonObject()); - - String roomId = roomKeyContent.room_id; - String sessionId = roomKeyContent.session_id; - String sessionKey = roomKeyContent.session_key; - String senderKey = roomKeyEvent.senderKey(); - Map keysClaimed = new HashMap<>(); - List forwarding_curve25519_key_chain = null; - - if (TextUtils.isEmpty(roomId) || TextUtils.isEmpty(sessionId) || TextUtils.isEmpty(sessionKey)) { - Log.e(LOG_TAG, "## onRoomKeyEvent() : Key event is missing fields"); - return; - } - - if (TextUtils.equals(roomKeyEvent.getType(), Event.EVENT_TYPE_FORWARDED_ROOM_KEY)) { - Log.d(LOG_TAG, "## onRoomKeyEvent(), forward adding key : roomId " + roomId + " sessionId " + sessionId - + " sessionKey " + sessionKey); // from " + event); - ForwardedRoomKeyContent forwardedRoomKeyContent = JsonUtils.toForwardedRoomKeyContent(roomKeyEvent.getContentAsJsonObject()); - - if (null == forwardedRoomKeyContent.forwarding_curve25519_key_chain) { - forwarding_curve25519_key_chain = new ArrayList<>(); - } else { - forwarding_curve25519_key_chain = new ArrayList<>(forwardedRoomKeyContent.forwarding_curve25519_key_chain); - } - - forwarding_curve25519_key_chain.add(senderKey); - - exportFormat = true; - senderKey = forwardedRoomKeyContent.sender_key; - if (null == senderKey) { - Log.e(LOG_TAG, "## onRoomKeyEvent() : forwarded_room_key event is missing sender_key field"); - return; - } - - String ed25519Key = forwardedRoomKeyContent.sender_claimed_ed25519_key; - - if (null == ed25519Key) { - Log.e(LOG_TAG, "## forwarded_room_key_event is missing sender_claimed_ed25519_key field"); - return; - } - - keysClaimed.put("ed25519", ed25519Key); - } else { - Log.d(LOG_TAG, "## onRoomKeyEvent(), Adding key : roomId " + roomId + " sessionId " + sessionId - + " sessionKey " + sessionKey); // from " + event); - - if (null == senderKey) { - Log.e(LOG_TAG, "## onRoomKeyEvent() : key event has no sender key (not encrypted?)"); - return; - } - - // inherit the claimed ed25519 key from the setup message - keysClaimed = roomKeyEvent.getKeysClaimed(); - } - - mOlmDevice.addInboundGroupSession(sessionId, sessionKey, roomId, senderKey, forwarding_curve25519_key_chain, keysClaimed, exportFormat); - - Map content = new HashMap<>(); - content.put("algorithm", roomKeyContent.algorithm); - content.put("room_id", roomKeyContent.room_id); - content.put("session_id", roomKeyContent.session_id); - content.put("sender_key", senderKey); - mSession.getCrypto().cancelRoomKeyRequest(content); - - onNewSession(senderKey, sessionId); - } - - /** - * Check if the some messages can be decrypted with a new session - * - * @param senderKey the session sender key - * @param sessionId the session id - */ - public void onNewSession(String senderKey, String sessionId) { - String k = senderKey + "|" + sessionId; - - Map> pending = mPendingEvents.get(k); - - if (null != pending) { - // Have another go at decrypting events sent with this session. - mPendingEvents.remove(k); - - Set timelineIds = pending.keySet(); - - for (String timelineId : timelineIds) { - List events = pending.get(timelineId); - - for (Event event : events) { - MXEventDecryptionResult result = null; - - try { - result = decryptEvent(event, TextUtils.isEmpty(timelineId) ? null : timelineId); - } catch (MXDecryptionException e) { - Log.e(LOG_TAG, "## onNewSession() : Still can't decrypt " + event.eventId + ". Error " + e.getMessage(), e); - event.setCryptoError(e.getCryptoError()); - } - - if (null != result) { - final Event fEvent = event; - final MXEventDecryptionResult fResut = result; - mSession.getCrypto().getUIHandler().post(new Runnable() { - @Override - public void run() { - fEvent.setClearData(fResut); - mSession.getDataHandler().onEventDecrypted(fEvent); - } - }); - Log.d(LOG_TAG, "## onNewSession() : successful re-decryption of " + event.eventId); - } - } - } - } - } - - @Override - public boolean hasKeysForKeyRequest(IncomingRoomKeyRequest request) { - return (null != request) - && (null != request.mRequestBody) - && mOlmDevice.hasInboundSessionKeys(request.mRequestBody.room_id, request.mRequestBody.sender_key, request.mRequestBody.session_id); - } - - @Override - public void shareKeysWithDevice(final IncomingRoomKeyRequest request) { - // sanity checks - if ((null == request) || (null == request.mRequestBody)) { - return; - } - - final String userId = request.mUserId; - - mSession.getCrypto().getDeviceList().downloadKeys(Arrays.asList(userId), false, new ApiCallback>() { - @Override - public void onSuccess(MXUsersDevicesMap devicesMap) { - final String deviceId = request.mDeviceId; - final MXDeviceInfo deviceInfo = mSession.getCrypto().mCryptoStore.getUserDevice(deviceId, userId); - - if (null != deviceInfo) { - final RoomKeyRequestBody body = request.mRequestBody; - - Map> devicesByUser = new HashMap<>(); - devicesByUser.put(userId, new ArrayList<>(Arrays.asList(deviceInfo))); - - mSession.getCrypto().ensureOlmSessionsForDevices(devicesByUser, new ApiCallback>() { - @Override - public void onSuccess(MXUsersDevicesMap map) { - MXOlmSessionResult olmSessionResult = map.getObject(deviceId, userId); - - if ((null == olmSessionResult) || (null == olmSessionResult.mSessionId)) { - // no session with this device, probably because there - // were no one-time keys. - // - // ensureOlmSessionsForUsers has already done the logging, - // so just skip it. - return; - } - - Log.d(LOG_TAG, "## shareKeysWithDevice() : sharing keys for session " + body.sender_key + "|" + body.session_id - + " with device " + userId + ":" + deviceId); - - MXOlmInboundGroupSession2 inboundGroupSession = mSession.getCrypto() - .getOlmDevice().getInboundGroupSession(body.session_id, body.sender_key, body.room_id); - - Map payloadJson = new HashMap<>(); - payloadJson.put("type", Event.EVENT_TYPE_FORWARDED_ROOM_KEY); - payloadJson.put("content", inboundGroupSession.exportKeys()); - - Map encodedPayload = mSession.getCrypto().encryptMessage(payloadJson, Arrays.asList(deviceInfo)); - MXUsersDevicesMap> sendToDeviceMap = new MXUsersDevicesMap<>(); - sendToDeviceMap.setObject(encodedPayload, userId, deviceId); - - Log.d(LOG_TAG, "## shareKeysWithDevice() : sending to " + userId + ":" + deviceId); - mSession.getCryptoRestClient().sendToDevice(Event.EVENT_TYPE_MESSAGE_ENCRYPTED, sendToDeviceMap, new ApiCallback() { - @Override - public void onSuccess(Void info) { - Log.d(LOG_TAG, "## shareKeysWithDevice() : sent to " + userId + ":" + deviceId); - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "## shareKeysWithDevice() : sendToDevice " + userId + ":" + deviceId + " failed " + e.getMessage(), e); - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "## shareKeysWithDevice() : sendToDevice " + userId + ":" + deviceId + " failed " + e.getMessage()); - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "## shareKeysWithDevice() : sendToDevice " + userId + ":" + deviceId + " failed " + e.getMessage(), e); - } - }); - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "## shareKeysWithDevice() : ensureOlmSessionsForDevices " + userId + ":" + deviceId + " failed " - + e.getMessage(), e); - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "## shareKeysWithDevice() : ensureOlmSessionsForDevices " + userId + ":" + deviceId + " failed " + e.getMessage()); - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "## shareKeysWithDevice() : ensureOlmSessionsForDevices " + userId + ":" + deviceId + " failed " - + e.getMessage(), e); - } - }); - } else { - Log.e(LOG_TAG, "## shareKeysWithDevice() : ensureOlmSessionsForDevices " + userId + ":" + deviceId + " not found"); - } - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "## shareKeysWithDevice() : downloadKeys " + userId + " failed " + e.getMessage(), e); - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "## shareKeysWithDevice() : downloadKeys " + userId + " failed " + e.getMessage()); - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "## shareKeysWithDevice() : downloadKeys " + userId + " failed " + e.getMessage(), e); - } - }); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/megolm/MXMegolmEncryption.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/megolm/MXMegolmEncryption.java deleted file mode 100644 index bb5904dc..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/megolm/MXMegolmEncryption.java +++ /dev/null @@ -1,714 +0,0 @@ -/* - * Copyright 2015 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.crypto.algorithms.megolm; - -import android.text.TextUtils; - -import com.google.gson.JsonElement; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import im.vector.matrix.android.internal.legacy.MXSession; -import im.vector.matrix.android.internal.legacy.crypto.MXCrypto; -import im.vector.matrix.android.internal.legacy.crypto.MXCryptoAlgorithms; -import im.vector.matrix.android.internal.legacy.crypto.MXCryptoError; -import im.vector.matrix.android.internal.legacy.crypto.MXOlmDevice; -import im.vector.matrix.android.internal.legacy.crypto.algorithms.IMXEncrypting; -import im.vector.matrix.android.internal.legacy.crypto.data.MXDeviceInfo; -import im.vector.matrix.android.internal.legacy.crypto.data.MXOlmSessionResult; -import im.vector.matrix.android.internal.legacy.crypto.data.MXQueuedEncryption; -import im.vector.matrix.android.internal.legacy.crypto.data.MXUsersDevicesMap; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.SimpleApiCallback; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.util.JsonUtils; -import im.vector.matrix.android.internal.legacy.util.Log; - -public class MXMegolmEncryption implements IMXEncrypting { - private static final String LOG_TAG = MXMegolmEncryption.class.getSimpleName(); - - private MXSession mSession; - private MXCrypto mCrypto; - - // The id of the room we will be sending to. - private String mRoomId; - - private String mDeviceId; - - // OutboundSessionInfo. Null if we haven't yet started setting one up. Note - // that even if this is non-null, it may not be ready for use (in which - // case outboundSession.shareOperation will be non-null.) - private MXOutboundSessionInfo mOutboundSession; - - // true when there is an HTTP operation in progress - private boolean mShareOperationIsProgress; - - private final List mPendingEncryptions = new ArrayList<>(); - - // Session rotation periods - private int mSessionRotationPeriodMsgs; - private int mSessionRotationPeriodMs; - - @Override - public void initWithMatrixSession(MXSession matrixSession, String roomId) { - mSession = matrixSession; - mCrypto = matrixSession.getCrypto(); - - mRoomId = roomId; - mDeviceId = matrixSession.getCredentials().getDeviceId(); - - // Default rotation periods - // TODO: Make it configurable via parameters - mSessionRotationPeriodMsgs = 100; - mSessionRotationPeriodMs = 7 * 24 * 3600 * 1000; - } - - /** - * @return a snapshot of the pending encryptions - */ - private List getPendingEncryptions() { - List list = new ArrayList<>(); - - synchronized (mPendingEncryptions) { - list.addAll(mPendingEncryptions); - } - - return list; - } - - @Override - public void encryptEventContent(final JsonElement eventContent, - final String eventType, - final List userIds, - final ApiCallback callback) { - // Queue the encryption request - // It will be processed when everything is set up - MXQueuedEncryption queuedEncryption = new MXQueuedEncryption(); - - queuedEncryption.mEventContent = eventContent; - queuedEncryption.mEventType = eventType; - queuedEncryption.mApiCallback = callback; - - synchronized (mPendingEncryptions) { - mPendingEncryptions.add(queuedEncryption); - } - - final long t0 = System.currentTimeMillis(); - Log.d(LOG_TAG, "## encryptEventContent () starts"); - - getDevicesInRoom(userIds, new ApiCallback>() { - - /** - * A network error has been received while encrypting - * @param e the exception - */ - private void dispatchNetworkError(Exception e) { - Log.e(LOG_TAG, "## encryptEventContent() : onNetworkError " + e.getMessage(), e); - List queuedEncryptions = getPendingEncryptions(); - - for (MXQueuedEncryption queuedEncryption : queuedEncryptions) { - queuedEncryption.mApiCallback.onNetworkError(e); - } - - synchronized (mPendingEncryptions) { - mPendingEncryptions.removeAll(queuedEncryptions); - } - } - - /** - * A matrix error has been received while encrypting - * @param e the exception - */ - private void dispatchMatrixError(MatrixError e) { - Log.e(LOG_TAG, "## encryptEventContent() : onMatrixError " + e.getMessage()); - - List queuedEncryptions = getPendingEncryptions(); - - for (MXQueuedEncryption queuedEncryption : queuedEncryptions) { - queuedEncryption.mApiCallback.onMatrixError(e); - } - - synchronized (mPendingEncryptions) { - mPendingEncryptions.removeAll(queuedEncryptions); - } - } - - /** - * An unexpected error has been received while encrypting - * @param e the exception - */ - private void dispatchUnexpectedError(Exception e) { - Log.e(LOG_TAG, "## onUnexpectedError() : onMatrixError " + e.getMessage(), e); - - List queuedEncryptions = getPendingEncryptions(); - - for (MXQueuedEncryption queuedEncryption : queuedEncryptions) { - queuedEncryption.mApiCallback.onUnexpectedError(e); - } - - synchronized (mPendingEncryptions) { - mPendingEncryptions.removeAll(queuedEncryptions); - } - } - - @Override - public void onSuccess(MXUsersDevicesMap devicesInRoom) { - ensureOutboundSession(devicesInRoom, new ApiCallback() { - @Override - public void onSuccess(final MXOutboundSessionInfo session) { - mCrypto.getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - Log.d(LOG_TAG, "## encryptEventContent () processPendingEncryptions after " + (System.currentTimeMillis() - t0) + "ms"); - processPendingEncryptions(session); - } - }); - } - - @Override - public void onNetworkError(Exception e) { - dispatchNetworkError(e); - } - - @Override - public void onMatrixError(MatrixError e) { - dispatchMatrixError(e); - } - - @Override - public void onUnexpectedError(Exception e) { - dispatchUnexpectedError(e); - } - }); - } - - @Override - public void onNetworkError(Exception e) { - dispatchNetworkError(e); - } - - @Override - public void onMatrixError(MatrixError e) { - dispatchMatrixError(e); - } - - @Override - public void onUnexpectedError(Exception e) { - dispatchUnexpectedError(e); - } - }); - - - } - - /** - * Prepare a new session. - * - * @return the session description - */ - private MXOutboundSessionInfo prepareNewSessionInRoom() { - MXOlmDevice olmDevice = mCrypto.getOlmDevice(); - final String sessionId = olmDevice.createOutboundGroupSession(); - - Map keysClaimedMap = new HashMap<>(); - keysClaimedMap.put("ed25519", olmDevice.getDeviceEd25519Key()); - - olmDevice.addInboundGroupSession(sessionId, olmDevice.getSessionKey(sessionId), mRoomId, olmDevice.getDeviceCurve25519Key(), - new ArrayList(), keysClaimedMap, false); - - return new MXOutboundSessionInfo(sessionId); - } - - /** - * Ensure the outbound session - * - * @param devicesInRoom the devices list - * @param callback the asynchronous callback. - */ - private void ensureOutboundSession(MXUsersDevicesMap devicesInRoom, final ApiCallback callback) { - MXOutboundSessionInfo session = mOutboundSession; - - if ((null == session) - // Need to make a brand new session? - || session.needsRotation(mSessionRotationPeriodMsgs, mSessionRotationPeriodMs) - // Determine if we have shared with anyone we shouldn't have - || session.sharedWithTooManyDevices(devicesInRoom)) { - mOutboundSession = session = prepareNewSessionInRoom(); - } - - if (mShareOperationIsProgress) { - Log.d(LOG_TAG, "## ensureOutboundSessionInRoom() : already in progress"); - // Key share already in progress - return; - } - - final MXOutboundSessionInfo fSession = session; - - Map> shareMap = new HashMap<>(); - - List userIds = devicesInRoom.getUserIds(); - - for (String userId : userIds) { - List deviceIds = devicesInRoom.getUserDeviceIds(userId); - - for (String deviceId : deviceIds) { - MXDeviceInfo deviceInfo = devicesInRoom.getObject(deviceId, userId); - - if (null == fSession.mSharedWithDevices.getObject(deviceId, userId)) { - if (!shareMap.containsKey(userId)) { - shareMap.put(userId, new ArrayList()); - } - - shareMap.get(userId).add(deviceInfo); - } - } - } - - shareKey(fSession, shareMap, new ApiCallback() { - @Override - public void onSuccess(Void anything) { - mShareOperationIsProgress = false; - if (null != callback) { - callback.onSuccess(fSession); - } - } - - @Override - public void onNetworkError(final Exception e) { - Log.e(LOG_TAG, "## ensureOutboundSessionInRoom() : shareKey onNetworkError " + e.getMessage(), e); - - if (null != callback) { - callback.onNetworkError(e); - } - mShareOperationIsProgress = false; - } - - @Override - public void onMatrixError(final MatrixError e) { - Log.e(LOG_TAG, "## ensureOutboundSessionInRoom() : shareKey onMatrixError " + e.getMessage()); - - if (null != callback) { - callback.onMatrixError(e); - } - mShareOperationIsProgress = false; - } - - @Override - public void onUnexpectedError(final Exception e) { - Log.e(LOG_TAG, "## ensureOutboundSessionInRoom() : shareKey onUnexpectedError " + e.getMessage(), e); - - if (null != callback) { - callback.onUnexpectedError(e); - } - mShareOperationIsProgress = false; - } - }); - - } - - /** - * Share the device key to a list of users - * - * @param session the session info - * @param devicesByUsers the devices map - * @param callback the asynchronous callback - */ - private void shareKey(final MXOutboundSessionInfo session, - final Map> devicesByUsers, - final ApiCallback callback) { - // nothing to send, the task is done - if (0 == devicesByUsers.size()) { - Log.d(LOG_TAG, "## shareKey() : nothing more to do"); - - if (null != callback) { - mCrypto.getUIHandler().post(new Runnable() { - @Override - public void run() { - callback.onSuccess(null); - } - }); - } - - return; - } - - // reduce the map size to avoid request timeout when there are too devices (Users size * devices per user) - Map> subMap = new HashMap<>(); - - final List userIds = new ArrayList<>(); - int devicesCount = 0; - - for (String userId : devicesByUsers.keySet()) { - List devicesList = devicesByUsers.get(userId); - - userIds.add(userId); - subMap.put(userId, devicesList); - - devicesCount += devicesList.size(); - - if (devicesCount > 100) { - break; - } - } - - Log.d(LOG_TAG, "## shareKey() ; userId " + userIds); - shareUserDevicesKey(session, subMap, new ApiCallback() { - @Override - public void onSuccess(Void info) { - mCrypto.getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - for (String userId : userIds) { - devicesByUsers.remove(userId); - } - shareKey(session, devicesByUsers, callback); - } - }); - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "## shareKey() ; userIds " + userIds + " failed " + e.getMessage(), e); - if (null != callback) { - callback.onNetworkError(e); - } - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "## shareKey() ; userIds " + userIds + " failed " + e.getMessage()); - if (null != callback) { - callback.onMatrixError(e); - } - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "## shareKey() ; userIds " + userIds + " failed " + e.getMessage(), e); - if (null != callback) { - callback.onUnexpectedError(e); - } - } - }); - } - - /** - * Share the device keys of a an user - * - * @param session the session info - * @param devicesByUser the devices map - * @param callback the asynchronous callback - */ - private void shareUserDevicesKey(final MXOutboundSessionInfo session, - final Map> devicesByUser, - final ApiCallback callback) { - final String sessionKey = mCrypto.getOlmDevice().getSessionKey(session.mSessionId); - final int chainIndex = mCrypto.getOlmDevice().getMessageIndex(session.mSessionId); - - Map submap = new HashMap<>(); - submap.put("algorithm", MXCryptoAlgorithms.MXCRYPTO_ALGORITHM_MEGOLM); - submap.put("room_id", mRoomId); - submap.put("session_id", session.mSessionId); - submap.put("session_key", sessionKey); - submap.put("chain_index", chainIndex); - - final Map payload = new HashMap<>(); - payload.put("type", Event.EVENT_TYPE_ROOM_KEY); - payload.put("content", submap); - - final long t0 = System.currentTimeMillis(); - Log.d(LOG_TAG, "## shareUserDevicesKey() : starts"); - - mCrypto.ensureOlmSessionsForDevices(devicesByUser, new ApiCallback>() { - @Override - public void onSuccess(final MXUsersDevicesMap results) { - mCrypto.getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - Log.d(LOG_TAG, "## shareUserDevicesKey() : ensureOlmSessionsForDevices succeeds after " + (System.currentTimeMillis() - t0) + " ms"); - MXUsersDevicesMap> contentMap = new MXUsersDevicesMap<>(); - - boolean haveTargets = false; - List userIds = results.getUserIds(); - - for (String userId : userIds) { - List devicesToShareWith = devicesByUser.get(userId); - - for (MXDeviceInfo deviceInfo : devicesToShareWith) { - String deviceID = deviceInfo.deviceId; - - MXOlmSessionResult sessionResult = results.getObject(deviceID, userId); - - if ((null == sessionResult) || (null == sessionResult.mSessionId)) { - // no session with this device, probably because there - // were no one-time keys. - // - // we could send them a to_device message anyway, as a - // signal that they have missed out on the key sharing - // message because of the lack of keys, but there's not - // much point in that really; it will mostly serve to clog - // up to_device inboxes. - // - // ensureOlmSessionsForUsers has already done the logging, - // so just skip it. - continue; - } - - Log.d(LOG_TAG, "## shareUserDevicesKey() : Sharing keys with device " + userId + ":" + deviceID); - //noinspection ArraysAsListWithZeroOrOneArgument,ArraysAsListWithZeroOrOneArgument - contentMap.setObject(mCrypto.encryptMessage(payload, Arrays.asList(sessionResult.mDevice)), userId, deviceID); - haveTargets = true; - } - } - - if (haveTargets && !mCrypto.hasBeenReleased()) { - final long t0 = System.currentTimeMillis(); - Log.d(LOG_TAG, "## shareUserDevicesKey() : has target"); - - mSession.getCryptoRestClient().sendToDevice(Event.EVENT_TYPE_MESSAGE_ENCRYPTED, contentMap, new ApiCallback() { - @Override - public void onSuccess(Void info) { - mCrypto.getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - Log.d(LOG_TAG, "## shareUserDevicesKey() : sendToDevice succeeds after " - + (System.currentTimeMillis() - t0) + " ms"); - - // Add the devices we have shared with to session.sharedWithDevices. - // we deliberately iterate over devicesByUser (ie, the devices we - // attempted to share with) rather than the contentMap (those we did - // share with), because we don't want to try to claim a one-time-key - // for dead devices on every message. - for (String userId : devicesByUser.keySet()) { - List devicesToShareWith = devicesByUser.get(userId); - - for (MXDeviceInfo deviceInfo : devicesToShareWith) { - session.mSharedWithDevices.setObject(chainIndex, userId, deviceInfo.deviceId); - } - } - - mCrypto.getUIHandler().post(new Runnable() { - @Override - public void run() { - if (null != callback) { - callback.onSuccess(null); - } - } - }); - } - }); - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "## shareUserDevicesKey() : sendToDevice onNetworkError " + e.getMessage(), e); - - if (null != callback) { - callback.onNetworkError(e); - } - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "## shareUserDevicesKey() : sendToDevice onMatrixError " + e.getMessage()); - - if (null != callback) { - callback.onMatrixError(e); - } - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "## shareUserDevicesKey() : sendToDevice onUnexpectedError " + e.getMessage(), e); - - if (null != callback) { - callback.onUnexpectedError(e); - } - } - }); - } else { - Log.d(LOG_TAG, "## shareUserDevicesKey() : no need to sharekey"); - - if (null != callback) { - mCrypto.getUIHandler().post(new Runnable() { - @Override - public void run() { - callback.onSuccess(null); - } - }); - } - } - } - }); - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "## shareUserDevicesKey() : ensureOlmSessionsForDevices failed " + e.getMessage(), e); - - if (null != callback) { - callback.onNetworkError(e); - } - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "## shareUserDevicesKey() : ensureOlmSessionsForDevices failed " + e.getMessage()); - - if (null != callback) { - callback.onMatrixError(e); - } - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "## shareUserDevicesKey() : ensureOlmSessionsForDevices failed " + e.getMessage(), e); - - if (null != callback) { - callback.onUnexpectedError(e); - } - } - }); - } - - /** - * process the pending encryptions - */ - private void processPendingEncryptions(MXOutboundSessionInfo session) { - if (null != session) { - List queuedEncryptions = getPendingEncryptions(); - - // Everything is in place, encrypt all pending events - for (MXQueuedEncryption queuedEncryption : queuedEncryptions) { - Map payloadJson = new HashMap<>(); - - payloadJson.put("room_id", mRoomId); - payloadJson.put("type", queuedEncryption.mEventType); - payloadJson.put("content", queuedEncryption.mEventContent); - - String payloadString = JsonUtils.convertToUTF8(JsonUtils.canonicalize(JsonUtils.getGson(false).toJsonTree(payloadJson)).toString()); - String ciphertext = mCrypto.getOlmDevice().encryptGroupMessage(session.mSessionId, payloadString); - - final Map map = new HashMap<>(); - map.put("algorithm", MXCryptoAlgorithms.MXCRYPTO_ALGORITHM_MEGOLM); - map.put("sender_key", mCrypto.getOlmDevice().getDeviceCurve25519Key()); - map.put("ciphertext", ciphertext); - map.put("session_id", session.mSessionId); - - // Include our device ID so that recipients can send us a - // m.new_device message if they don't have our session key. - map.put("device_id", mDeviceId); - - final MXQueuedEncryption fQueuedEncryption = queuedEncryption; - mCrypto.getUIHandler().post(new Runnable() { - @Override - public void run() { - fQueuedEncryption.mApiCallback.onSuccess(JsonUtils.getGson(false).toJsonTree(map)); - } - }); - - session.mUseCount++; - } - - synchronized (mPendingEncryptions) { - mPendingEncryptions.removeAll(queuedEncryptions); - } - } - } - - /** - * Get the list of devices which can encrypt data to. - * This method must be called in getDecryptingThreadHandler() thread. - * - * @param userIds the user ids whose devices must be checked. - * @param callback the asynchronous callback - */ - private void getDevicesInRoom(final List userIds, final ApiCallback> callback) { - // We are happy to use a cached version here: we assume that if we already - // have a list of the user's devices, then we already share an e2e room - // with them, which means that they will have announced any new devices via - // an m.new_device. - mCrypto.getDeviceList().downloadKeys(userIds, false, new SimpleApiCallback>(callback) { - @Override - public void onSuccess(final MXUsersDevicesMap devices) { - mCrypto.getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - boolean encryptToVerifiedDevicesOnly = mCrypto.getGlobalBlacklistUnverifiedDevices() - || mCrypto.isRoomBlacklistUnverifiedDevices(mRoomId); - - final MXUsersDevicesMap devicesInRoom = new MXUsersDevicesMap<>(); - final MXUsersDevicesMap unknownDevices = new MXUsersDevicesMap<>(); - - List userIds = devices.getUserIds(); - - for (String userId : userIds) { - List deviceIds = devices.getUserDeviceIds(userId); - - for (String deviceId : deviceIds) { - MXDeviceInfo deviceInfo = devices.getObject(deviceId, userId); - - if (mCrypto.warnOnUnknownDevices() && deviceInfo.isUnknown()) { - // The device is not yet known by the user - unknownDevices.setObject(deviceInfo, userId, deviceId); - continue; - } - - if (deviceInfo.isBlocked()) { - // Remove any blocked devices - continue; - } - - if (!deviceInfo.isVerified() && encryptToVerifiedDevicesOnly) { - continue; - } - - if (TextUtils.equals(deviceInfo.identityKey(), mCrypto.getOlmDevice().getDeviceCurve25519Key())) { - // Don't bother sending to ourself - continue; - } - - devicesInRoom.setObject(deviceInfo, userId, deviceId); - } - } - - mCrypto.getUIHandler().post(new Runnable() { - @Override - public void run() { - // Check if any of these devices are not yet known to the user. - // if so, warn the user so they can verify or ignore. - if (0 != unknownDevices.getMap().size()) { - callback.onMatrixError(new MXCryptoError(MXCryptoError.UNKNOWN_DEVICES_CODE, - MXCryptoError.UNABLE_TO_ENCRYPT, MXCryptoError.UNKNOWN_DEVICES_REASON, unknownDevices)); - } else { - callback.onSuccess(devicesInRoom); - } - } - }); - } - }); - } - }); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/megolm/MXOutboundSessionInfo.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/megolm/MXOutboundSessionInfo.java deleted file mode 100644 index b57e928a..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/megolm/MXOutboundSessionInfo.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2015 OpenMarket Ltd - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.crypto.algorithms.megolm; - -import im.vector.matrix.android.internal.legacy.crypto.data.MXDeviceInfo; -import im.vector.matrix.android.internal.legacy.util.Log; -import im.vector.matrix.android.internal.legacy.crypto.data.MXUsersDevicesMap; - -import java.util.List; - -public class MXOutboundSessionInfo { - private static final String LOG_TAG = MXOutboundSessionInfo.class.getSimpleName(); - - // When the session was created - private final long mCreationTime; - - // The id of the session - public final String mSessionId; - - // Number of times this session has been used - public int mUseCount; - - // Devices with which we have shared the session key - // userId -> {deviceId -> msgindex} - public final MXUsersDevicesMap mSharedWithDevices; - - // constructor - public MXOutboundSessionInfo(String sessionId) { - mSessionId = sessionId; - mSharedWithDevices = new MXUsersDevicesMap<>(); - mCreationTime = System.currentTimeMillis(); - mUseCount = 0; - } - - public boolean needsRotation(int rotationPeriodMsgs, int rotationPeriodMs) { - boolean needsRotation = false; - long sessionLifetime = System.currentTimeMillis() - mCreationTime; - - if ((mUseCount >= rotationPeriodMsgs) || (sessionLifetime >= rotationPeriodMs)) { - Log.d(LOG_TAG, "## needsRotation() : Rotating megolm session after " + mUseCount + ", " + sessionLifetime + "ms"); - needsRotation = true; - } - - return needsRotation; - } - - /** - * Determine if this session has been shared with devices which it shouldn't have been. - * - * @param devicesInRoom the devices map - * @return true if we have shared the session with devices which aren't in devicesInRoom. - */ - public boolean sharedWithTooManyDevices(MXUsersDevicesMap devicesInRoom) { - List userIds = mSharedWithDevices.getUserIds(); - - for (String userId : userIds) { - if (null == devicesInRoom.getUserDeviceIds(userId)) { - Log.d(LOG_TAG, "## sharedWithTooManyDevices() : Starting new session because we shared with " + userId); - return true; - } - - List deviceIds = mSharedWithDevices.getUserDeviceIds(userId); - - for (String deviceId : deviceIds) { - if (null == devicesInRoom.getObject(deviceId, userId)) { - Log.d(LOG_TAG, "## sharedWithTooManyDevices() : Starting new session because we shared with " + userId + ":" + deviceId); - return true; - } - } - } - - return false; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/olm/MXOlmDecryption.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/olm/MXOlmDecryption.java deleted file mode 100644 index 20ca52f6..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/olm/MXOlmDecryption.java +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright 2015 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.crypto.algorithms.olm; - -import android.text.TextUtils; - -import com.google.gson.JsonElement; -import com.google.gson.JsonParser; - -import im.vector.matrix.android.internal.legacy.MXSession; -import im.vector.matrix.android.internal.legacy.crypto.IncomingRoomKeyRequest; -import im.vector.matrix.android.internal.legacy.crypto.MXCryptoError; -import im.vector.matrix.android.internal.legacy.crypto.MXDecryptionException; -import im.vector.matrix.android.internal.legacy.crypto.MXEventDecryptionResult; -import im.vector.matrix.android.internal.legacy.crypto.MXOlmDevice; -import im.vector.matrix.android.internal.legacy.crypto.algorithms.IMXDecrypting; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.OlmEventContent; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.OlmPayloadContent; -import im.vector.matrix.android.internal.legacy.util.JsonUtils; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * An interface for encrypting data - */ -public class MXOlmDecryption implements IMXDecrypting { - private static final String LOG_TAG = "MXOlmDecryption"; - - // The olm device interface - private MXOlmDevice mOlmDevice; - - // the matrix session - private MXSession mSession; - - @Override - public void initWithMatrixSession(MXSession matrixSession) { - mSession = matrixSession; - mOlmDevice = matrixSession.getCrypto().getOlmDevice(); - } - - @Override - public MXEventDecryptionResult decryptEvent(Event event, String timeline) throws MXDecryptionException { - // sanity check - if (null == event) { - Log.e(LOG_TAG, "## decryptEvent() : null event"); - return null; - } - - OlmEventContent olmEventContent = JsonUtils.toOlmEventContent(event.getWireContent().getAsJsonObject()); - String deviceKey = olmEventContent.sender_key; - Map ciphertext = olmEventContent.ciphertext; - - if (null == ciphertext) { - Log.e(LOG_TAG, "## decryptEvent() : missing cipher text"); - throw new MXDecryptionException(new MXCryptoError(MXCryptoError.MISSING_CIPHER_TEXT_ERROR_CODE, - MXCryptoError.UNABLE_TO_DECRYPT, MXCryptoError.MISSING_CIPHER_TEXT_REASON)); - } - - if (!ciphertext.containsKey(mOlmDevice.getDeviceCurve25519Key())) { - Log.e(LOG_TAG, "## decryptEvent() : our device " + mOlmDevice.getDeviceCurve25519Key() - + " is not included in recipients. Event " + event.getContentAsJsonObject()); - throw new MXDecryptionException(new MXCryptoError(MXCryptoError.NOT_INCLUDE_IN_RECIPIENTS_ERROR_CODE, - MXCryptoError.UNABLE_TO_DECRYPT, MXCryptoError.NOT_INCLUDED_IN_RECIPIENT_REASON)); - } - - // The message for myUser - Map message = (Map) ciphertext.get(mOlmDevice.getDeviceCurve25519Key()); - String payloadString = decryptMessage(message, deviceKey); - - if (null == payloadString) { - Log.e(LOG_TAG, "## decryptEvent() Failed to decrypt Olm event (id= " + event.eventId + " ) from " + deviceKey); - throw new MXDecryptionException(new MXCryptoError(MXCryptoError.BAD_ENCRYPTED_MESSAGE_ERROR_CODE, - MXCryptoError.UNABLE_TO_DECRYPT, MXCryptoError.BAD_ENCRYPTED_MESSAGE_REASON)); - } - - JsonElement payload = new JsonParser().parse(JsonUtils.convertFromUTF8(payloadString)); - - if (null == payload) { - Log.e(LOG_TAG, "## decryptEvent failed : null payload"); - throw new MXDecryptionException(new MXCryptoError(MXCryptoError.UNABLE_TO_DECRYPT_ERROR_CODE, - MXCryptoError.UNABLE_TO_DECRYPT, MXCryptoError.MISSING_CIPHER_TEXT_REASON)); - } - - OlmPayloadContent olmPayloadContent = JsonUtils.toOlmPayloadContent(payload); - - if (TextUtils.isEmpty(olmPayloadContent.recipient)) { - String reason = String.format(MXCryptoError.ERROR_MISSING_PROPERTY_REASON, "recipient"); - Log.e(LOG_TAG, "## decryptEvent() : " + reason); - throw new MXDecryptionException(new MXCryptoError(MXCryptoError.MISSING_PROPERTY_ERROR_CODE, - MXCryptoError.UNABLE_TO_DECRYPT, reason)); - } - - if (!TextUtils.equals(olmPayloadContent.recipient, mSession.getMyUserId())) { - Log.e(LOG_TAG, "## decryptEvent() : Event " + event.eventId + ": Intended recipient " + olmPayloadContent.recipient - + " does not match our id " + mSession.getMyUserId()); - throw new MXDecryptionException(new MXCryptoError(MXCryptoError.BAD_RECIPIENT_ERROR_CODE, - MXCryptoError.UNABLE_TO_DECRYPT, String.format(MXCryptoError.BAD_RECIPIENT_REASON, olmPayloadContent.recipient))); - } - - if (null == olmPayloadContent.recipient_keys) { - Log.e(LOG_TAG, "## decryptEvent() : Olm event (id=" + event.eventId - + ") contains no " + "'recipient_keys' property; cannot prevent unknown-key attack"); - throw new MXDecryptionException(new MXCryptoError(MXCryptoError.MISSING_PROPERTY_ERROR_CODE, - MXCryptoError.UNABLE_TO_DECRYPT, String.format(MXCryptoError.ERROR_MISSING_PROPERTY_REASON, "recipient_keys"))); - } - - String ed25519 = olmPayloadContent.recipient_keys.get("ed25519"); - - if (!TextUtils.equals(ed25519, mOlmDevice.getDeviceEd25519Key())) { - Log.e(LOG_TAG, "## decryptEvent() : Event " + event.eventId + ": Intended recipient ed25519 key " + ed25519 + " did not match ours"); - throw new MXDecryptionException(new MXCryptoError(MXCryptoError.BAD_RECIPIENT_KEY_ERROR_CODE, - MXCryptoError.UNABLE_TO_DECRYPT, MXCryptoError.BAD_RECIPIENT_KEY_REASON)); - } - - if (TextUtils.isEmpty(olmPayloadContent.sender)) { - Log.e(LOG_TAG, "## decryptEvent() : Olm event (id=" + event.eventId - + ") contains no 'sender' property; cannot prevent unknown-key attack"); - throw new MXDecryptionException(new MXCryptoError(MXCryptoError.MISSING_PROPERTY_ERROR_CODE, - MXCryptoError.UNABLE_TO_DECRYPT, String.format(MXCryptoError.ERROR_MISSING_PROPERTY_REASON, "sender"))); - } - - if (!TextUtils.equals(olmPayloadContent.sender, event.getSender())) { - Log.e(LOG_TAG, "Event " + event.eventId + ": original sender " + olmPayloadContent.sender - + " does not match reported sender " + event.getSender()); - throw new MXDecryptionException(new MXCryptoError(MXCryptoError.FORWARDED_MESSAGE_ERROR_CODE, - MXCryptoError.UNABLE_TO_DECRYPT, String.format(MXCryptoError.FORWARDED_MESSAGE_REASON, olmPayloadContent.sender))); - } - - if (!TextUtils.equals(olmPayloadContent.room_id, event.roomId)) { - Log.e(LOG_TAG, "## decryptEvent() : Event " + event.eventId + ": original room " + olmPayloadContent.room_id - + " does not match reported room " + event.roomId); - throw new MXDecryptionException(new MXCryptoError(MXCryptoError.BAD_ROOM_ERROR_CODE, - MXCryptoError.UNABLE_TO_DECRYPT, String.format(MXCryptoError.BAD_ROOM_REASON, olmPayloadContent.room_id))); - } - - if (null == olmPayloadContent.keys) { - Log.e(LOG_TAG, "## decryptEvent failed : null keys"); - throw new MXDecryptionException(new MXCryptoError(MXCryptoError.UNABLE_TO_DECRYPT_ERROR_CODE, - MXCryptoError.UNABLE_TO_DECRYPT, MXCryptoError.MISSING_CIPHER_TEXT_REASON)); - } - - MXEventDecryptionResult result = new MXEventDecryptionResult(); - result.mClearEvent = payload; - result.mSenderCurve25519Key = deviceKey; - result.mClaimedEd25519Key = olmPayloadContent.keys.get("ed25519"); - - return result; - } - - @Override - public void onRoomKeyEvent(Event event) { - // No impact for olm - } - - @Override - public void onNewSession(String senderKey, String sessionId) { - // No impact for olm - } - - @Override - public boolean hasKeysForKeyRequest(IncomingRoomKeyRequest request) { - return false; - } - - @Override - public void shareKeysWithDevice(IncomingRoomKeyRequest request) { - } - - /** - * Attempt to decrypt an Olm message. - * - * @param theirDeviceIdentityKey the Curve25519 identity key of the sender. - * @param message message object, with 'type' and 'body' fields. - * @return payload, if decrypted successfully. - */ - private String decryptMessage(Map message, String theirDeviceIdentityKey) { - Set sessionIdsSet = mOlmDevice.getSessionIds(theirDeviceIdentityKey); - - List sessionIds; - - if (null == sessionIdsSet) { - sessionIds = new ArrayList<>(); - } else { - sessionIds = new ArrayList<>(sessionIdsSet); - } - - String messageBody = (String) message.get("body"); - Integer messageType = null; - - Object typeAsVoid = message.get("type"); - - if (null != typeAsVoid) { - if (typeAsVoid instanceof Double) { - messageType = new Integer(((Double) typeAsVoid).intValue()); - } else if (typeAsVoid instanceof Integer) { - messageType = (Integer) typeAsVoid; - } else if (typeAsVoid instanceof Long) { - messageType = new Integer(((Long) typeAsVoid).intValue()); - } - } - - if ((null == messageBody) || (null == messageType)) { - return null; - } - - // Try each session in turn - // decryptionErrors = {}; - for (String sessionId : sessionIds) { - String payload = mOlmDevice.decryptMessage(messageBody, messageType, sessionId, theirDeviceIdentityKey); - - if (null != payload) { - Log.d(LOG_TAG, "## decryptMessage() : Decrypted Olm message from " + theirDeviceIdentityKey + " with session " + sessionId); - return payload; - } else { - boolean foundSession = mOlmDevice.matchesSession(theirDeviceIdentityKey, sessionId, messageType, messageBody); - - if (foundSession) { - // Decryption failed, but it was a prekey message matching this - // session, so it should have worked. - Log.e(LOG_TAG, "## decryptMessage() : Error decrypting prekey message with existing session id " + sessionId + ":TODO"); - return null; - } - } - } - - if (messageType != 0) { - // not a prekey message, so it should have matched an existing session, but it - // didn't work. - - if (sessionIds.size() == 0) { - Log.e(LOG_TAG, "## decryptMessage() : No existing sessions"); - } else { - Log.e(LOG_TAG, "## decryptMessage() : Error decrypting non-prekey message with existing sessions"); - } - - return null; - } - - // prekey message which doesn't match any existing sessions: make a new - // session. - Map res = mOlmDevice.createInboundSession(theirDeviceIdentityKey, messageType, messageBody); - - if (null == res) { - Log.e(LOG_TAG, "## decryptMessage() : Error decrypting non-prekey message with existing sessions"); - return null; - } - - Log.d(LOG_TAG, "## decryptMessage() : Created new inbound Olm session get id " + res.get("session_id") + " with " + theirDeviceIdentityKey); - - return res.get("payload"); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/olm/MXOlmEncryption.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/olm/MXOlmEncryption.java deleted file mode 100644 index e3db32cd..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/algorithms/olm/MXOlmEncryption.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2015 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.crypto.algorithms.olm; - -import android.text.TextUtils; - -import com.google.gson.JsonElement; - -import im.vector.matrix.android.internal.legacy.MXSession; -import im.vector.matrix.android.internal.legacy.crypto.MXCrypto; -import im.vector.matrix.android.internal.legacy.crypto.algorithms.IMXEncrypting; -import im.vector.matrix.android.internal.legacy.crypto.data.MXDeviceInfo; -import im.vector.matrix.android.internal.legacy.crypto.data.MXOlmSessionResult; -import im.vector.matrix.android.internal.legacy.crypto.data.MXUsersDevicesMap; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.SimpleApiCallback; -import im.vector.matrix.android.internal.legacy.util.JsonUtils; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class MXOlmEncryption implements IMXEncrypting { - private MXCrypto mCrypto; - private String mRoomId; - - @Override - public void initWithMatrixSession(MXSession matrixSession, String roomId) { - mCrypto = matrixSession.getCrypto(); - mRoomId = roomId; - } - - /** - * @return the stored device keys for a user. - */ - private List getUserDevices(final String userId) { - Map map = mCrypto.getCryptoStore().getUserDevices(userId); - return (null != map) ? new ArrayList<>(map.values()) : new ArrayList(); - } - - @Override - public void encryptEventContent(final JsonElement eventContent, - final String eventType, - final List userIds, - final ApiCallback callback) { - // pick the list of recipients based on the membership list. - // - // TODO: there is a race condition here! What if a new user turns up - ensureSession(userIds, new SimpleApiCallback(callback) { - @Override - public void onSuccess(Void info) { - List deviceInfos = new ArrayList<>(); - - for (String userId : userIds) { - List devices = getUserDevices(userId); - - if (null != devices) { - for (MXDeviceInfo device : devices) { - String key = device.identityKey(); - - if (TextUtils.equals(key, mCrypto.getOlmDevice().getDeviceCurve25519Key())) { - // Don't bother setting up session to ourself - continue; - } - - if (device.isBlocked()) { - // Don't bother setting up sessions with blocked users - continue; - } - - deviceInfos.add(device); - } - } - } - - Map messageMap = new HashMap<>(); - messageMap.put("room_id", mRoomId); - messageMap.put("type", eventType); - messageMap.put("content", eventContent); - - mCrypto.encryptMessage(messageMap, deviceInfos); - callback.onSuccess(JsonUtils.getGson(false).toJsonTree(messageMap)); - } - } - ); - } - - /** - * Ensure that the session - * - * @param users the user ids list - * @param callback the asynchronous callback - */ - private void ensureSession(final List users, final ApiCallback callback) { - mCrypto.getDeviceList().downloadKeys(users, false, new SimpleApiCallback>(callback) { - @Override - public void onSuccess(MXUsersDevicesMap info) { - mCrypto.ensureOlmSessionsForUsers(users, new SimpleApiCallback>(callback) { - @Override - public void onSuccess(MXUsersDevicesMap result) { - if (null != callback) { - callback.onSuccess(null); - } - } - }); - } - }); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXDeviceInfo.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXDeviceInfo.java deleted file mode 100755 index 5bb2e7bc..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXDeviceInfo.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.crypto.data; - -import android.text.TextUtils; - -import java.io.Serializable; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class MXDeviceInfo implements Serializable { - private static final long serialVersionUID = 20129670646382964L; - // - //private static final String LOG_TAG = "MXDeviceInfo"; - - // This device is a new device and the user was not warned it has been added. - public static final int DEVICE_VERIFICATION_UNKNOWN = -1; - - // The user has not yet verified this device. - public static final int DEVICE_VERIFICATION_UNVERIFIED = 0; - - // The user has verified this device. - public static final int DEVICE_VERIFICATION_VERIFIED = 1; - - // The user has blocked this device. - public static final int DEVICE_VERIFICATION_BLOCKED = 2; - - /** - * The id of this device. - */ - public String deviceId; - - /** - * the user id - */ - public String userId; - - /** - * The list of algorithms supported by this device. - */ - public List algorithms; - - /** - * A map from : to >. - */ - public Map keys; - - /** - * The signature of this MXDeviceInfo. - * A map from : to >. - */ - public Map> signatures; - - /* - * Additional data from the home server. - */ - public Map unsigned; - - /** - * Verification state of this device. - */ - public int mVerified; - - /** - * Constructor - */ - public MXDeviceInfo() { - mVerified = DEVICE_VERIFICATION_UNKNOWN; - } - - /** - * Constructor - * - * @param aDeviceId the device id - */ - public MXDeviceInfo(String aDeviceId) { - deviceId = aDeviceId; - mVerified = DEVICE_VERIFICATION_UNKNOWN; - } - - /** - * Tells if the device is unknown - * - * @return true if the device is unknown - */ - public boolean isUnknown() { - return mVerified == DEVICE_VERIFICATION_UNKNOWN; - } - - /** - * Tells if the device is verified. - * - * @return true if the device is verified - */ - public boolean isVerified() { - return mVerified == DEVICE_VERIFICATION_VERIFIED; - } - - /** - * Tells if the device is unverified. - * - * @return true if the device is unverified - */ - public boolean isUnverified() { - return mVerified == DEVICE_VERIFICATION_UNVERIFIED; - } - - /** - * Tells if the device is blocked. - * - * @return true if the device is blocked - */ - public boolean isBlocked() { - return mVerified == DEVICE_VERIFICATION_BLOCKED; - } - - /** - * @return the fingerprint - */ - public String fingerprint() { - if ((null != keys) && !TextUtils.isEmpty(deviceId)) { - return keys.get("ed25519:" + deviceId); - } - - return null; - } - - /** - * @return the identity key - */ - public String identityKey() { - if ((null != keys) && !TextUtils.isEmpty(deviceId)) { - return keys.get("curve25519:" + deviceId); - } - - return null; - } - - /** - * @return the display name - */ - public String displayName() { - if (null != unsigned) { - return (String) unsigned.get("device_display_name"); - } - - return null; - } - - /** - * @return the signed data map - */ - public Map signalableJSONDictionary() { - Map map = new HashMap<>(); - - map.put("device_id", deviceId); - - if (null != userId) { - map.put("user_id", userId); - } - - if (null != algorithms) { - map.put("algorithms", algorithms); - } - - if (null != keys) { - map.put("keys", keys); - } - - return map; - } - - /** - * @return a dictionary of the parameters - */ - public Map JSONDictionary() { - Map JSONDictionary = new HashMap<>(); - - JSONDictionary.put("device_id", deviceId); - - if (null != userId) { - JSONDictionary.put("user_id", userId); - } - - if (null != algorithms) { - JSONDictionary.put("algorithms", algorithms); - } - - if (null != keys) { - JSONDictionary.put("keys", keys); - } - - if (null != signatures) { - JSONDictionary.put("signatures", signatures); - } - - if (null != unsigned) { - JSONDictionary.put("unsigned", unsigned); - } - - return JSONDictionary; - } - - @Override - public java.lang.String toString() { - return "MXDeviceInfo " + userId + ":" + deviceId; - } -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXEncryptEventContentResult.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXEncryptEventContentResult.java deleted file mode 100755 index 76a67847..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXEncryptEventContentResult.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.crypto.data; - -import com.google.gson.JsonElement; - -import java.io.Serializable; - -public class MXEncryptEventContentResult implements Serializable { - //public static final String LOG_TAG = "MXEncryptEventContentResult"; - - /** - * The event content - */ - public final JsonElement mEventContent; - - /** - * the event type - */ - public final String mEventType; - - /** - * Constructor - * - * @param eventContent the eventContent - * @param eventType the eventType - */ - public MXEncryptEventContentResult(JsonElement eventContent, String eventType) { - mEventContent = eventContent; - mEventType = eventType; - } -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXKey.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXKey.java deleted file mode 100755 index 7666bda2..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXKey.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.crypto.data; - -import android.text.TextUtils; - -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class MXKey implements Serializable { - private static final String LOG_TAG = "MXKey"; - /** - * Key types. - */ - public static final String KEY_CURVE_25519_TYPE = "curve25519"; - public static final String KEY_SIGNED_CURVE_25519_TYPE = "signed_curve25519"; - //public static final String KEY_ED_25519_TYPE = "ed25519"; - - /** - * The type of the key. - */ - public String type; - - /** - * The id of the key. - */ - public String keyId; - - /** - * The key. - */ - public String value; - - /** - * signature user Id to [deviceid][signature] - */ - public Map> signatures; - - /** - * Default constructor - */ - public MXKey() { - } - - /** - * Convert a map to a MXKey - * - * @param map the map to convert - */ - public MXKey(Map> map) { - if ((null != map) && (map.size() > 0)) { - List mapKeys = new ArrayList<>(map.keySet()); - - String firstEntry = mapKeys.get(0); - setKeyFullId(firstEntry); - - Map params = map.get(firstEntry); - value = (String) params.get("key"); - signatures = (Map>) params.get("signatures"); - } - } - - /** - * @return the key full id - */ - public String getKeyFullId() { - return type + ":" + keyId; - } - - /** - * Update the key fields with a key full id - * - * @param keyFullId the key full id - */ - private void setKeyFullId(String keyFullId) { - if (!TextUtils.isEmpty(keyFullId)) { - try { - String[] components = keyFullId.split(":"); - - if (components.length == 2) { - type = components[0]; - keyId = components[1]; - } - } catch (Exception e) { - Log.e(LOG_TAG, "## setKeyFullId() failed : " + e.getMessage(), e); - } - } - } - - /** - * @return the signed data map - */ - public Map signalableJSONDictionary() { - Map map = new HashMap<>(); - - if (null != value) { - map.put("key", value); - } - - return map; - } - - /** - * Returns a signature for an user Id and a signkey - * - * @param userId the user id - * @param signkey the sign key - * @return the signature - */ - public String signatureForUserId(String userId, String signkey) { - // sanity checks - if (!TextUtils.isEmpty(userId) && !TextUtils.isEmpty(signkey)) { - if ((null != signatures) && signatures.containsKey(userId)) { - return signatures.get(userId).get(signkey); - } - } - - return null; - } -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXOlmInboundGroupSession.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXOlmInboundGroupSession.java deleted file mode 100755 index 45713015..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXOlmInboundGroupSession.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.crypto.data; - -import im.vector.matrix.android.internal.legacy.util.Log; - -import org.matrix.olm.OlmInboundGroupSession; - -import java.io.Serializable; - -import java.util.Map; - - -/** - * This class adds more context to a OLMInboundGroupSession object. - * This allows additional checks. The class implements NSCoding so that the context can be stored. - */ -public class MXOlmInboundGroupSession implements Serializable { - // - private static final String LOG_TAG = "OlmInboundGroupSession"; - - // The associated olm inbound group session. - public OlmInboundGroupSession mSession; - - // The room in which this session is used. - public String mRoomId; - - // The base64-encoded curve25519 key of the sender. - public String mSenderKey; - - // Other keys the sender claims. - public Map mKeysClaimed; - - /** - * Constructor - * - * @param sessionKey the session key - */ - public MXOlmInboundGroupSession(String sessionKey) { - try { - mSession = new OlmInboundGroupSession(sessionKey); - } catch (Exception e) { - Log.e(LOG_TAG, "Cannot create : " + e.getMessage(), e); - } - } -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXOlmInboundGroupSession2.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXOlmInboundGroupSession2.java deleted file mode 100755 index d98838cd..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXOlmInboundGroupSession2.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.crypto.data; - -import android.text.TextUtils; - -import im.vector.matrix.android.internal.legacy.crypto.MXCryptoAlgorithms; -import im.vector.matrix.android.internal.legacy.util.Log; -import org.matrix.olm.OlmInboundGroupSession; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - - -/** - * This class adds more context to a OLMInboundGroupSession object. - * This allows additional checks. The class implements NSCoding so that the context can be stored. - */ -public class MXOlmInboundGroupSession2 implements Serializable { - // - private static final String LOG_TAG = "OlmInboundGroupSession"; - - // define a serialVersionUID to avoid having to redefine the class after updates - private static final long serialVersionUID = 201702011617L; - - // The associated olm inbound group session. - public OlmInboundGroupSession mSession; - - // The room in which this session is used. - public String mRoomId; - - // The base64-encoded curve25519 key of the sender. - public String mSenderKey; - - // Other keys the sender claims. - public Map mKeysClaimed; - - // Devices which forwarded this session to us (normally empty). - public List mForwardingCurve25519KeyChain = new ArrayList<>(); - - /** - * Constructor - * - * @param prevFormatSession the previous session format - */ - public MXOlmInboundGroupSession2(MXOlmInboundGroupSession prevFormatSession) { - mSession = prevFormatSession.mSession; - mRoomId = prevFormatSession.mRoomId; - mSenderKey = prevFormatSession.mSenderKey; - mKeysClaimed = prevFormatSession.mKeysClaimed; - } - - /** - * Constructor - * - * @param sessionKey the session key - * @param isImported true if it is an imported session key - */ - public MXOlmInboundGroupSession2(String sessionKey, boolean isImported) { - try { - if (!isImported) { - mSession = new OlmInboundGroupSession(sessionKey); - } else { - mSession = OlmInboundGroupSession.importSession(sessionKey); - } - } catch (Exception e) { - Log.e(LOG_TAG, "Cannot create : " + e.getMessage(), e); - } - } - - /** - * Create a new instance from the provided keys map. - * - * @param map the map - * @throws Exception if the data are invalid - */ - public MXOlmInboundGroupSession2(Map map) throws Exception { - try { - mSession = OlmInboundGroupSession.importSession((String) map.get("session_key")); - - if (!TextUtils.equals(mSession.sessionIdentifier(), (String) map.get("session_id"))) { - throw new Exception("Mismatched group session Id"); - } - - mSenderKey = (String) map.get("sender_key"); - mKeysClaimed = (Map) map.get("sender_claimed_keys"); - mRoomId = (String) map.get("room_id"); - } catch (Exception e) { - throw new Exception(e.getMessage()); - } - } - - /** - * Export the inbound group session keys - * - * @return the inbound group session as map if the operation succeeds - */ - public Map exportKeys() { - Map map = new HashMap<>(); - - try { - if (null == mForwardingCurve25519KeyChain) { - mForwardingCurve25519KeyChain = new ArrayList<>(); - } - - map.put("sender_claimed_ed25519_key", mKeysClaimed.get("ed25519")); - map.put("forwardingCurve25519KeyChain", mForwardingCurve25519KeyChain); - map.put("sender_key", mSenderKey); - map.put("sender_claimed_keys", mKeysClaimed); - map.put("room_id", mRoomId); - map.put("session_id", mSession.sessionIdentifier()); - map.put("session_key", mSession.export(mSession.getFirstKnownIndex())); - map.put("algorithm", MXCryptoAlgorithms.MXCRYPTO_ALGORITHM_MEGOLM); - } catch (Exception e) { - map = null; - Log.e(LOG_TAG, "## export() : senderKey " + mSenderKey + " failed " + e.getMessage(), e); - } - - return map; - } - - /** - * @return the first known message index - */ - public Long getFirstKnownIndex() { - if (null != mSession) { - try { - return mSession.getFirstKnownIndex(); - } catch (Exception e) { - Log.e(LOG_TAG, "## getFirstKnownIndex() : getFirstKnownIndex failed " + e.getMessage(), e); - } - } - - return null; - } - - /** - * Export the session for a message index. - * - * @param messageIndex the message index - * @return the exported data - */ - public String exportSession(long messageIndex) { - if (null != mSession) { - try { - return mSession.export(messageIndex); - } catch (Exception e) { - Log.e(LOG_TAG, "## exportSession() : export failed " + e.getMessage(), e); - } - } - - return null; - } -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXOlmSessionResult.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXOlmSessionResult.java deleted file mode 100755 index 9f9d55a7..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXOlmSessionResult.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.crypto.data; - -import java.io.Serializable; - -public class MXOlmSessionResult implements Serializable { - /** - * the device - */ - public final MXDeviceInfo mDevice; - - /** - * Base64 olm session id. - * null if no session could be established. - */ - public String mSessionId; - - /** - * Constructor - * - * @param device the device - * @param sessionId the olm session id - */ - public MXOlmSessionResult(MXDeviceInfo device, String sessionId) { - mDevice = device; - mSessionId = sessionId; - } -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXQueuedEncryption.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXQueuedEncryption.java deleted file mode 100755 index b134e2d2..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXQueuedEncryption.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.crypto.data; - -import com.google.gson.JsonElement; - -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; - -public class MXQueuedEncryption { - - /** - * The data to encrypt. - */ - public JsonElement mEventContent; - public String mEventType; - - /** - * the asynchronous callback - */ - public ApiCallback mApiCallback; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXUsersDevicesMap.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXUsersDevicesMap.java deleted file mode 100755 index 8b1cdbb4..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/crypto/data/MXUsersDevicesMap.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.crypto.data; - -import android.text.TextUtils; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -public class MXUsersDevicesMap implements Serializable { - - // The device keys as returned by the homeserver: a map of a map (userId -> deviceId -> Object). - private final Map> mMap = new HashMap<>(); - - /** - * @return the inner map - */ - public Map> getMap() { - return mMap; - } - - /** - * Default constructor constructor - */ - public MXUsersDevicesMap() { - } - - /** - * The constructor - * - * @param map the map - */ - public MXUsersDevicesMap(Map> map) { - if (null != map) { - Set keys = map.keySet(); - - for (String key : keys) { - mMap.put(key, new HashMap<>(map.get(key))); - } - } - } - - /** - * @return a deep copy - */ - public MXUsersDevicesMap deepCopy() { - MXUsersDevicesMap copy = new MXUsersDevicesMap<>(); - - Set keys = mMap.keySet(); - - for (String key : keys) { - copy.mMap.put(key, new HashMap<>(mMap.get(key))); - } - - return copy; - } - - /** - * @return the user Ids - */ - public List getUserIds() { - return new ArrayList<>(mMap.keySet()); - } - - /** - * Provides the device ids list for an user id - * - * @param userId the user id - * @return the device ids list - */ - public List getUserDeviceIds(String userId) { - if (!TextUtils.isEmpty(userId) && mMap.containsKey(userId)) { - return new ArrayList<>(mMap.get(userId).keySet()); - } - - return null; - } - - /** - * Provides the object for a device id and an user Id - * - * @param deviceId the device id - * @param userId the object id - * @return the object - */ - public E getObject(String deviceId, String userId) { - if (!TextUtils.isEmpty(userId) && mMap.containsKey(userId) && !TextUtils.isEmpty(deviceId)) { - return mMap.get(userId).get(deviceId); - } - - return null; - } - - /** - * Set an object for a dedicated user Id and device Id - * - * @param object the object to set - * @param userId the user Id - * @param deviceId the device id - */ - public void setObject(E object, String userId, String deviceId) { - if ((null != object) && !TextUtils.isEmpty(userId) && !TextUtils.isEmpty(deviceId)) { - Map subMap = mMap.get(userId); - - if (null == subMap) { - subMap = new HashMap<>(); - mMap.put(userId, subMap); - } - - subMap.put(deviceId, object); - } - } - - /** - * Defines the objects map for an user Id - * - * @param objectsPerDevices the objects maps - * @param userId the user id - */ - public void setObjects(Map objectsPerDevices, String userId) { - if (!TextUtils.isEmpty(userId)) { - if (null == objectsPerDevices) { - mMap.remove(userId); - } else { - mMap.put(userId, new HashMap<>(objectsPerDevices)); - } - } - } - - /** - * Removes objects for a dedicated user - * - * @param userId the user id. - */ - public void removeUserObjects(String userId) { - if (!TextUtils.isEmpty(userId)) { - mMap.remove(userId); - } - } - - /** - * Clear the internal dictionary - */ - public void removeAllObjects() { - mMap.clear(); - } - - /** - * Add entries from another MXUsersDevicesMap - * - * @param other the other one - */ - public void addEntriesFromMap(MXUsersDevicesMap other) { - if (null != other) { - mMap.putAll(other.getMap()); - } - } - - @Override - public java.lang.String toString() { - if (null != mMap) { - return "MXUsersDevicesMap " + mMap.toString(); - } else { - return "MXDeviceInfo : null map"; - } - } -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/DataRetriever.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/DataRetriever.java deleted file mode 100644 index 5bf6e465..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/DataRetriever.java +++ /dev/null @@ -1,423 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.data; - -import android.os.Looper; -import android.text.TextUtils; - -import im.vector.matrix.android.internal.legacy.data.store.IMXStore; -import im.vector.matrix.android.internal.legacy.data.timeline.EventTimeline; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.SimpleApiCallback; -import im.vector.matrix.android.internal.legacy.rest.client.RoomsRestClient; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.rest.model.TokensChunkEvents; -import im.vector.matrix.android.internal.legacy.util.FilterUtil; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -/** - * Layer for retrieving data either from the storage implementation, or from the server if the information is not available. - */ -public class DataRetriever { - private static final String LOG_TAG = DataRetriever.class.getSimpleName(); - - private RoomsRestClient mRestClient; - - private final Map mPendingForwardRequestTokenByRoomId = new HashMap<>(); - private final Map mPendingBackwardRequestTokenByRoomId = new HashMap<>(); - private final Map mPendingRemoteRequestTokenByRoomId = new HashMap<>(); - - public RoomsRestClient getRoomsRestClient() { - return mRestClient; - } - - public void setRoomsRestClient(final RoomsRestClient client) { - mRestClient = client; - } - - /** - * Provides the cached messages for a dedicated roomId - * - * @param store the store. - * @param roomId the roomId - * @return the events list, null if the room does not exist - */ - public Collection getCachedRoomMessages(final IMXStore store, final String roomId) { - return store.getRoomMessages(roomId); - } - - /** - * Cancel any history requests for a dedicated room - * - * @param roomId the room id. - */ - public void cancelHistoryRequests(final String roomId) { - Log.d(LOG_TAG, "## cancelHistoryRequests() : roomId " + roomId); - - clearPendingToken(mPendingForwardRequestTokenByRoomId, roomId); - clearPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); - } - - /** - * Cancel any request history requests for a dedicated room - * - * @param roomId the room id. - */ - public void cancelRemoteHistoryRequest(final String roomId) { - Log.d(LOG_TAG, "## cancelRemoteHistoryRequest() : roomId " + roomId); - - clearPendingToken(mPendingRemoteRequestTokenByRoomId, roomId); - } - - /** - * Get the event associated with the eventId and roomId - * Look in the store before hitting the rest client. - * - * @param store the store to look in - * @param roomId the room Id - * @param eventId the eventId - * @param callback the callback - */ - public void getEvent(final IMXStore store, final String roomId, final String eventId, final ApiCallback callback) { - final Event event = store.getEvent(eventId, roomId); - if (event == null) { - mRestClient.getEvent(roomId, eventId, callback); - } else { - callback.onSuccess(event); - } - } - - /** - * Trigger a back pagination for a dedicated room from Token. - * - * @param store the store to use - * @param roomId the room Id - * @param token the start token. - * @param limit the maximum number of messages to retrieve - * @param withLazyLoading true when lazy loading is enabled - * @param callback the callback - */ - public void backPaginate(final IMXStore store, - final String roomId, - final String token, - final int limit, - final boolean withLazyLoading, - final ApiCallback callback) { - // reach the marker end - if (TextUtils.equals(token, Event.PAGINATE_BACK_TOKEN_END)) { - // nothing more to provide - final android.os.Handler handler = new android.os.Handler(Looper.getMainLooper()); - - // call the callback with a delay - // to reproduce the same behaviour as a network request. - // except for the initial request. - Runnable r = new Runnable() { - @Override - public void run() { - handler.postDelayed(new Runnable() { - public void run() { - callback.onSuccess(new TokensChunkEvents()); - } - }, 0); - } - }; - - handler.post(r); - - return; - } - - Log.d(LOG_TAG, "## backPaginate() : starts for roomId " + roomId); - - TokensChunkEvents storageResponse = store.getEarlierMessages(roomId, token, limit); - - putPendingToken(mPendingBackwardRequestTokenByRoomId, roomId, token); - - if (storageResponse != null) { - final android.os.Handler handler = new android.os.Handler(Looper.getMainLooper()); - final TokensChunkEvents fStorageResponse = storageResponse; - - Log.d(LOG_TAG, "## backPaginate() : some data has been retrieved into the local storage (" + fStorageResponse.chunk.size() + " events)"); - - // call the callback with a delay - // to reproduce the same behaviour as a network request. - // except for the initial request. - Runnable r = new Runnable() { - @Override - public void run() { - handler.postDelayed(new Runnable() { - public void run() { - String expectedToken = getPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); - Log.d(LOG_TAG, "## backPaginate() : local store roomId " + roomId + " token " + token + " vs " + expectedToken); - - if (TextUtils.equals(expectedToken, token)) { - clearPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); - callback.onSuccess(fStorageResponse); - } - } - }, 0); - } - }; - - Thread t = new Thread(r); - t.start(); - } else { - Log.d(LOG_TAG, "## backPaginate() : trigger a remote request"); - - mRestClient.getRoomMessagesFrom(roomId, token, EventTimeline.Direction.BACKWARDS, limit, FilterUtil.createRoomEventFilter(withLazyLoading), - new SimpleApiCallback(callback) { - @Override - public void onSuccess(TokensChunkEvents tokensChunkEvents) { - String expectedToken = getPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); - - Log.d(LOG_TAG, "## backPaginate() succeeds : roomId " + roomId + " token " + token + " vs " + expectedToken); - - if (TextUtils.equals(expectedToken, token)) { - clearPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); - - // Watch for the one event overlap - Event oldestEvent = store.getOldestEvent(roomId); - - if (tokensChunkEvents.chunk.size() != 0) { - tokensChunkEvents.chunk.get(0).mToken = tokensChunkEvents.start; - - // there is no more data on server side - if (null == tokensChunkEvents.end) { - tokensChunkEvents.end = Event.PAGINATE_BACK_TOKEN_END; - } - - tokensChunkEvents.chunk.get(tokensChunkEvents.chunk.size() - 1).mToken = tokensChunkEvents.end; - - Event firstReturnedEvent = tokensChunkEvents.chunk.get(0); - if ((oldestEvent != null) && (firstReturnedEvent != null) - && TextUtils.equals(oldestEvent.eventId, firstReturnedEvent.eventId)) { - tokensChunkEvents.chunk.remove(0); - } - - store.storeRoomEvents(roomId, tokensChunkEvents, EventTimeline.Direction.BACKWARDS); - } - - Log.d(LOG_TAG, "## backPaginate() succeed : roomId " + roomId - + " token " + token - + " got " + tokensChunkEvents.chunk.size()); - callback.onSuccess(tokensChunkEvents); - } - } - - private void logErrorMessage(String expectedToken, String errorMessage) { - Log.e(LOG_TAG, "## backPaginate() failed : roomId " + roomId - + " token " + token - + " expected " + expectedToken - + " with " + errorMessage); - } - - @Override - public void onNetworkError(Exception e) { - String expectedToken = getPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); - logErrorMessage(expectedToken, e.getMessage()); - - // dispatch only if it is expected - if (TextUtils.equals(token, expectedToken)) { - clearPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); - callback.onNetworkError(e); - } - } - - @Override - public void onMatrixError(MatrixError e) { - String expectedToken = getPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); - logErrorMessage(expectedToken, e.getMessage()); - - // dispatch only if it is expected - if (TextUtils.equals(token, expectedToken)) { - clearPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); - callback.onMatrixError(e); - } - } - - @Override - public void onUnexpectedError(Exception e) { - String expectedToken = getPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); - logErrorMessage(expectedToken, e.getMessage()); - - // dispatch only if it is expected - if (TextUtils.equals(token, expectedToken)) { - clearPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); - callback.onUnexpectedError(e); - } - } - }); - } - } - - /** - * Trigger a forward pagination for a dedicated room from Token. - * - * @param store the store to use - * @param roomId the room Id - * @param token the start token. - * @param withLazyLoading true when lazy loading is enabled - * @param callback the callback - */ - private void forwardPaginate(final IMXStore store, - final String roomId, - final String token, - final boolean withLazyLoading, - final ApiCallback callback) { - putPendingToken(mPendingForwardRequestTokenByRoomId, roomId, token); - - mRestClient.getRoomMessagesFrom(roomId, token, EventTimeline.Direction.FORWARDS, RoomsRestClient.DEFAULT_MESSAGES_PAGINATION_LIMIT, - FilterUtil.createRoomEventFilter(withLazyLoading), - new SimpleApiCallback(callback) { - @Override - public void onSuccess(TokensChunkEvents tokensChunkEvents) { - if (TextUtils.equals(getPendingToken(mPendingForwardRequestTokenByRoomId, roomId), token)) { - clearPendingToken(mPendingForwardRequestTokenByRoomId, roomId); - store.storeRoomEvents(roomId, tokensChunkEvents, EventTimeline.Direction.FORWARDS); - callback.onSuccess(tokensChunkEvents); - } - } - }); - } - - /** - * Request messages than the given token. These will come from storage if available, from the server otherwise. - * - * @param store the store to use - * @param roomId the room id - * @param token the token to go back from. Null to start from live. - * @param direction the pagination direction - * @param withLazyLoading true when lazy loading is enabled - * @param callback the onComplete callback - */ - public void paginate(final IMXStore store, - final String roomId, - final String token, - final EventTimeline.Direction direction, - final boolean withLazyLoading, - final ApiCallback callback) { - if (direction == EventTimeline.Direction.BACKWARDS) { - backPaginate(store, roomId, token, RoomsRestClient.DEFAULT_MESSAGES_PAGINATION_LIMIT, withLazyLoading, callback); - } else { - forwardPaginate(store, roomId, token, withLazyLoading, callback); - } - } - - /** - * Request events to the server. The local cache is not used. - * The events will not be saved in the local storage. - * - * @param roomId the room id - * @param token the token to go back from. - * @param paginationCount the number of events to retrieve. - * @param withLazyLoading true when lazy loading is enabled - * @param callback the onComplete callback - */ - public void requestServerRoomHistory(final String roomId, - final String token, - final int paginationCount, - final boolean withLazyLoading, - final ApiCallback callback) { - putPendingToken(mPendingRemoteRequestTokenByRoomId, roomId, token); - - mRestClient.getRoomMessagesFrom(roomId, token, EventTimeline.Direction.BACKWARDS, paginationCount, FilterUtil.createRoomEventFilter(withLazyLoading), - new SimpleApiCallback(callback) { - @Override - public void onSuccess(TokensChunkEvents info) { - if (TextUtils.equals(getPendingToken(mPendingRemoteRequestTokenByRoomId, roomId), token)) { - if (info.chunk.size() != 0) { - info.chunk.get(0).mToken = info.start; - info.chunk.get(info.chunk.size() - 1).mToken = info.end; - } - - clearPendingToken(mPendingRemoteRequestTokenByRoomId, roomId); - callback.onSuccess(info); - } - } - }); - } - - //============================================================================================================== - // Pending token management - //============================================================================================================== - - /** - * Clear token for a dedicated room - * - * @param dict the token cache - * @param roomId the room id - */ - private void clearPendingToken(final Map dict, final String roomId) { - Log.d(LOG_TAG, "## clearPendingToken() : roomId " + roomId); - - if (null != roomId) { - synchronized (dict) { - dict.remove(roomId); - } - } - } - - /** - * Get the pending token for a dedicated room - * - * @param dict the token cache - * @param roomId the room Id - * @return the token - */ - private String getPendingToken(final Map dict, final String roomId) { - String expectedToken = "Not a valid token"; - - synchronized (dict) { - // token == null is a valid value - if (dict.containsKey(roomId)) { - expectedToken = dict.get(roomId); - - if (TextUtils.isEmpty(expectedToken)) { - expectedToken = null; - } - } - } - Log.d(LOG_TAG, "## getPendingToken() : roomId " + roomId + " token " + expectedToken); - - return expectedToken; - } - - /** - * Store a token for a dedicated room - * - * @param dict the token cache - * @param roomId the room id - * @param token the token - */ - private void putPendingToken(final Map dict, final String roomId, final String token) { - Log.d(LOG_TAG, "## putPendingToken() : roomId " + roomId + " token " + token); - - synchronized (dict) { - // null is allowed for a request - if (null == token) { - dict.put(roomId, ""); - } else { - dict.put(roomId, token); - } - } - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/MyUser.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/MyUser.java deleted file mode 100644 index f57fdc13..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/MyUser.java +++ /dev/null @@ -1,446 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.data; - -import android.os.Handler; -import android.os.Looper; - -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.SimpleApiCallback; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.rest.model.User; -import im.vector.matrix.android.internal.legacy.rest.model.pid.ThirdPartyIdentifier; -import im.vector.matrix.android.internal.legacy.rest.model.pid.ThreePid; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.util.ArrayList; -import java.util.List; - -/** - * Class representing the logged-in user. - */ -public class MyUser extends User { - - private static final String LOG_TAG = MyUser.class.getSimpleName(); - - // refresh status - private boolean mIsAvatarRefreshed = false; - private boolean mIsDisplayNameRefreshed = false; - private boolean mAre3PIdsLoaded = false; - - // the account info is refreshed in one row - // so, if there is a pending refresh the listeners are added to this list. - private transient List> mRefreshListeners; - - private transient final Handler mUiHandler; - - // linked emails to the account - private transient List mEmailIdentifiers = new ArrayList<>(); - // linked phone number to the account - private transient List mPhoneNumberIdentifiers = new ArrayList<>(); - - public MyUser(User user) { - clone(user); - - mUiHandler = new Handler(Looper.getMainLooper()); - } - - /** - * Update the user's display name. - * - * @param displayName the new name - * @param callback the async callback - */ - public void updateDisplayName(final String displayName, final ApiCallback callback) { - mDataHandler.getProfileRestClient().updateDisplayname(displayName, new SimpleApiCallback(callback) { - @Override - public void onSuccess(Void info) { - // Update the object member before calling the given callback - MyUser.this.displayname = displayName; - mDataHandler.getStore().setDisplayName(displayName, System.currentTimeMillis()); - - callback.onSuccess(info); - } - }); - } - - /** - * Update the user's avatar URL. - * - * @param avatarUrl the new avatar URL - * @param callback the async callback - */ - public void updateAvatarUrl(final String avatarUrl, final ApiCallback callback) { - mDataHandler.getProfileRestClient().updateAvatarUrl(avatarUrl, new SimpleApiCallback(callback) { - @Override - public void onSuccess(Void info) { - // Update the object member before calling the given callback - setAvatarUrl(avatarUrl); - mDataHandler.getStore().setAvatarURL(avatarUrl, System.currentTimeMillis()); - - callback.onSuccess(info); - } - }); - } - - /** - * Request a validation token for an email address 3Pid - * - * @param pid the pid to retrieve a token - * @param callback the callback when the operation is done - */ - public void requestEmailValidationToken(ThreePid pid, ApiCallback callback) { - if (null != pid) { - pid.requestEmailValidationToken(mDataHandler.getProfileRestClient(), null, false, callback); - } - } - - /** - * Request a validation token for a phone number 3Pid - * - * @param pid the pid to retrieve a token - * @param callback the callback when the operation is done - */ - public void requestPhoneNumberValidationToken(ThreePid pid, ApiCallback callback) { - if (null != pid) { - pid.requestPhoneNumberValidationToken(mDataHandler.getProfileRestClient(), false, callback); - } - } - - /** - * Add a new pid to the account. - * - * @param pid the pid to add. - * @param bind true to add it. - * @param callback the async callback - */ - public void add3Pid(final ThreePid pid, final boolean bind, final ApiCallback callback) { - if (null != pid) { - mDataHandler.getProfileRestClient().add3PID(pid, bind, new SimpleApiCallback(callback) { - @Override - public void onSuccess(Void info) { - // refresh the third party identifiers lists - refreshThirdPartyIdentifiers(callback); - } - }); - } - } - - /** - * Delete a 3pid from an account - * - * @param pid the pid to delete - * @param callback the async callback - */ - public void delete3Pid(final ThirdPartyIdentifier pid, final ApiCallback callback) { - if (null != pid) { - mDataHandler.getProfileRestClient().delete3PID(pid, new SimpleApiCallback(callback) { - @Override - public void onSuccess(Void info) { - // refresh the third party identifiers lists - refreshThirdPartyIdentifiers(callback); - } - }); - } - } - - /** - * Build the lists of identifiers - */ - private void buildIdentifiersLists() { - List identifiers = mDataHandler.getStore().thirdPartyIdentifiers(); - mEmailIdentifiers = new ArrayList<>(); - mPhoneNumberIdentifiers = new ArrayList<>(); - for (ThirdPartyIdentifier identifier : identifiers) { - switch (identifier.medium) { - case ThreePid.MEDIUM_EMAIL: - mEmailIdentifiers.add(identifier); - break; - case ThreePid.MEDIUM_MSISDN: - mPhoneNumberIdentifiers.add(identifier); - break; - } - } - } - - /** - * @return the list of linked emails - */ - public List getlinkedEmails() { - if (mEmailIdentifiers == null) { - buildIdentifiersLists(); - } - - return mEmailIdentifiers; - } - - /** - * @return the list of linked emails - */ - public List getlinkedPhoneNumbers() { - if (mPhoneNumberIdentifiers == null) { - buildIdentifiersLists(); - } - - return mPhoneNumberIdentifiers; - } - - //================================================================================ - // Refresh - //================================================================================ - - /** - * Refresh the user data if it is required - * - * @param callback callback when the job is done. - */ - public void refreshUserInfos(final ApiCallback callback) { - refreshUserInfos(false, callback); - } - - /** - * Refresh the user data if it is required - * - * @param callback callback when the job is done. - */ - public void refreshThirdPartyIdentifiers(final ApiCallback callback) { - mAre3PIdsLoaded = false; - refreshUserInfos(false, callback); - } - - - /** - * Refresh the user data if it is required - * - * @param skipPendingTest true to do not check if the refreshes started (private use) - * @param callback callback when the job is done. - */ - public void refreshUserInfos(boolean skipPendingTest, final ApiCallback callback) { - if (!skipPendingTest) { - boolean isPending; - - synchronized (this) { - // mRefreshListeners == null => no refresh in progress - // mRefreshListeners != null -> a refresh is in progress - isPending = (null != mRefreshListeners); - - if (null == mRefreshListeners) { - mRefreshListeners = new ArrayList<>(); - } - - if (null != callback) { - mRefreshListeners.add(callback); - } - } - - if (isPending) { - // please wait - return; - } - } - - if (!mIsDisplayNameRefreshed) { - refreshUserDisplayname(); - return; - } - - if (!mIsAvatarRefreshed) { - refreshUserAvatarUrl(); - return; - } - - if (!mAre3PIdsLoaded) { - refreshThirdPartyIdentifiers(); - return; - } - - synchronized (this) { - if (null != mRefreshListeners) { - for (ApiCallback listener : mRefreshListeners) { - try { - listener.onSuccess(null); - } catch (Exception e) { - Log.e(LOG_TAG, "## refreshUserInfos() : listener.onSuccess failed " + e.getMessage(), e); - } - } - } - - // no more pending refreshes - mRefreshListeners = null; - } - } - - /** - * Refresh the avatar url - */ - private void refreshUserAvatarUrl() { - mDataHandler.getProfileRestClient().avatarUrl(user_id, new SimpleApiCallback() { - @Override - public void onSuccess(String anAvatarUrl) { - if (mDataHandler.isAlive()) { - // local value - setAvatarUrl(anAvatarUrl); - // metadata file - mDataHandler.getStore().setAvatarURL(anAvatarUrl, System.currentTimeMillis()); - // user - mDataHandler.getStore().storeUser(MyUser.this); - - mIsAvatarRefreshed = true; - - // jump to the next items - refreshUserInfos(true, null); - } - } - - private void onError() { - if (mDataHandler.isAlive()) { - mUiHandler.postDelayed(new Runnable() { - @Override - public void run() { - refreshUserAvatarUrl(); - } - }, 1 * 1000); - } - } - - @Override - public void onNetworkError(Exception e) { - onError(); - } - - @Override - public void onMatrixError(final MatrixError e) { - // cannot retrieve this value, jump to the next items - mIsAvatarRefreshed = true; - refreshUserInfos(true, null); - } - - @Override - public void onUnexpectedError(final Exception e) { - // cannot retrieve this value, jump to the next items - mIsAvatarRefreshed = true; - refreshUserInfos(true, null); - } - }); - } - - /** - * Refresh the displayname. - */ - private void refreshUserDisplayname() { - mDataHandler.getProfileRestClient().displayname(user_id, new SimpleApiCallback() { - @Override - public void onSuccess(String aDisplayname) { - if (mDataHandler.isAlive()) { - // local value - displayname = aDisplayname; - // store metadata - mDataHandler.getStore().setDisplayName(aDisplayname, System.currentTimeMillis()); - - mIsDisplayNameRefreshed = true; - - // jump to the next items - refreshUserInfos(true, null); - } - } - - private void onError() { - if (mDataHandler.isAlive()) { - mUiHandler.postDelayed(new Runnable() { - @Override - public void run() { - refreshUserDisplayname(); - } - }, 1 * 1000); - } - } - - @Override - public void onNetworkError(Exception e) { - onError(); - } - - @Override - public void onMatrixError(final MatrixError e) { - // cannot retrieve this value, jump to the next items - mIsDisplayNameRefreshed = true; - refreshUserInfos(true, null); - } - - @Override - public void onUnexpectedError(final Exception e) { - // cannot retrieve this value, jump to the next items - mIsDisplayNameRefreshed = true; - refreshUserInfos(true, null); - } - }); - } - - /** - * Refresh the Third party identifiers i.e. the linked email to this account - */ - public void refreshThirdPartyIdentifiers() { - mDataHandler.getProfileRestClient().threePIDs(new SimpleApiCallback>() { - @Override - public void onSuccess(List identifiers) { - if (mDataHandler.isAlive()) { - // store - mDataHandler.getStore().setThirdPartyIdentifiers(identifiers); - - buildIdentifiersLists(); - - mAre3PIdsLoaded = true; - - // jump to the next items - refreshUserInfos(true, null); - } - } - - private void onError() { - if (mDataHandler.isAlive()) { - mUiHandler.postDelayed(new Runnable() { - @Override - public void run() { - refreshThirdPartyIdentifiers(); - } - }, 1 * 1000); - } - } - - @Override - public void onNetworkError(Exception e) { - onError(); - } - - @Override - public void onMatrixError(final MatrixError e) { - // cannot retrieve this value, jump to the next items - mAre3PIdsLoaded = true; - refreshUserInfos(true, null); - } - - @Override - public void onUnexpectedError(final Exception e) { - // cannot retrieve this value, jump to the next items - mAre3PIdsLoaded = true; - refreshUserInfos(true, null); - } - }); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/Pusher.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/Pusher.java deleted file mode 100644 index ad44666b..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/Pusher.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2015 OpenMarket 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.matrix.android.internal.legacy.data; - -import java.util.Map; - -public class Pusher { - public String pushkey; - public Object kind; - public String profileTag; - public String appId; - public String appDisplayName; - public String deviceDisplayName; - public String lang; - public Map data; - public Boolean append; - - - @Override - public java.lang.String toString() { - return "Pusher : \n\tappDisplayName " + appDisplayName + "\n\tdeviceDisplayName " + deviceDisplayName + "\n\tpushkey " + pushkey; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/Room.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/Room.java deleted file mode 100644 index 6f1358fc..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/Room.java +++ /dev/null @@ -1,2939 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.data; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.media.ExifInterface; -import android.media.MediaMetadataRetriever; -import android.media.MediaPlayer; -import android.net.Uri; -import android.os.AsyncTask; -import android.os.Handler; -import android.os.Looper; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.text.TextUtils; -import android.util.Pair; - -import com.google.gson.Gson; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.reflect.TypeToken; - -import java.io.File; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import im.vector.matrix.android.R; -import im.vector.matrix.android.internal.legacy.MXDataHandler; -import im.vector.matrix.android.internal.legacy.MXPatterns; -import im.vector.matrix.android.internal.legacy.call.MXCallsManager; -import im.vector.matrix.android.internal.legacy.crypto.MXCryptoError; -import im.vector.matrix.android.internal.legacy.crypto.data.MXEncryptEventContentResult; -import im.vector.matrix.android.internal.legacy.data.store.IMXStore; -import im.vector.matrix.android.internal.legacy.data.timeline.EventTimeline; -import im.vector.matrix.android.internal.legacy.data.timeline.EventTimelineFactory; -import im.vector.matrix.android.internal.legacy.db.MXMediasCache; -import im.vector.matrix.android.internal.legacy.listeners.IMXEventListener; -import im.vector.matrix.android.internal.legacy.listeners.MXEventListener; -import im.vector.matrix.android.internal.legacy.listeners.MXRoomEventListener; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.SimpleApiCallback; -import im.vector.matrix.android.internal.legacy.rest.client.AccountDataRestClient; -import im.vector.matrix.android.internal.legacy.rest.client.RoomsRestClient; -import im.vector.matrix.android.internal.legacy.rest.client.UrlPostTask; -import im.vector.matrix.android.internal.legacy.rest.model.BannedUser; -import im.vector.matrix.android.internal.legacy.rest.model.CreatedEvent; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.rest.model.PowerLevels; -import im.vector.matrix.android.internal.legacy.rest.model.ReceiptData; -import im.vector.matrix.android.internal.legacy.rest.model.RoomDirectoryVisibility; -import im.vector.matrix.android.internal.legacy.rest.model.RoomMember; -import im.vector.matrix.android.internal.legacy.rest.model.TokensChunkEvents; -import im.vector.matrix.android.internal.legacy.rest.model.message.FileInfo; -import im.vector.matrix.android.internal.legacy.rest.model.message.FileMessage; -import im.vector.matrix.android.internal.legacy.rest.model.message.ImageInfo; -import im.vector.matrix.android.internal.legacy.rest.model.message.ImageMessage; -import im.vector.matrix.android.internal.legacy.rest.model.message.LocationMessage; -import im.vector.matrix.android.internal.legacy.rest.model.message.Message; -import im.vector.matrix.android.internal.legacy.rest.model.message.ThumbnailInfo; -import im.vector.matrix.android.internal.legacy.rest.model.message.VideoInfo; -import im.vector.matrix.android.internal.legacy.rest.model.message.VideoMessage; -import im.vector.matrix.android.internal.legacy.rest.model.sync.InvitedRoomSync; -import im.vector.matrix.android.internal.legacy.rest.model.sync.RoomResponse; -import im.vector.matrix.android.internal.legacy.rest.model.sync.RoomSync; -import im.vector.matrix.android.internal.legacy.util.ImageUtils; -import im.vector.matrix.android.internal.legacy.util.JsonUtils; -import im.vector.matrix.android.internal.legacy.util.Log; - -/** - * Class representing a room and the interactions we have with it. - */ -public class Room { - - private static final String LOG_TAG = Room.class.getSimpleName(); - - // Account data - private RoomAccountData mAccountData = new RoomAccountData(); - - // handler - private MXDataHandler mDataHandler; - - // store - private IMXStore mStore; - - private String mMyUserId = null; - - // Map to keep track of the listeners the client adds vs. the ones we actually register to the global data handler. - // This is needed to find the right one when removing the listener. - private final Map mEventListeners = new HashMap<>(); - - // the user is leaving the room - private boolean mIsLeaving = false; - - // the room is syncing - private boolean mIsSyncing; - - // the unread messages count must be refreshed when the current sync is done. - private boolean mRefreshUnreadAfterSync = false; - - // the time line - private EventTimeline mTimeline; - - // initial sync callback. - private ApiCallback mOnInitialSyncCallback; - - // This is used to block live events and history requests until the state is fully processed and ready - private boolean mIsReady = false; - - // call conference user id - private String mCallConferenceUserId; - - // true when the current room is a left one - private boolean mIsLeft; - - /** - * Constructor - * FIXME All this @NonNull annotation must be also added to the class members and getters - * - * @param dataHandler the data handler - * @param store the store - * @param roomId the room id - */ - public Room(@NonNull final MXDataHandler dataHandler, @NonNull final IMXStore store, @NonNull final String roomId) { - mDataHandler = dataHandler; - mStore = store; - mMyUserId = mDataHandler.getUserId(); - mTimeline = EventTimelineFactory.liveTimeline(mDataHandler, this, roomId); - } - - /** - * @return the used data handler - */ - public MXDataHandler getDataHandler() { - return mDataHandler; - } - - /** - * @return the store in which the room is stored - */ - public IMXStore getStore() { - if (null == mStore) { - if (null != mDataHandler) { - mStore = mDataHandler.getStore(getRoomId()); - } - - if (null == mStore) { - Log.e(LOG_TAG, "## getStore() : cannot retrieve the store of " + getRoomId()); - } - } - - return mStore; - } - - /** - * Determine whether we should encrypt messages for invited users in this room. - *

- * Check here whether the invited members are allowed to read messages in the room history - * from the point they were invited onwards. - * - * @return true if we should encrypt messages for invited users. - */ - public boolean shouldEncryptForInvitedMembers() { - String historyVisibility = getState().history_visibility; - return !TextUtils.equals(historyVisibility, RoomState.HISTORY_VISIBILITY_JOINED); - } - - /** - * Tells if the room is a call conference one - * i.e. this room has been created to manage the call conference - * - * @return true if it is a call conference room. - */ - public boolean isConferenceUserRoom() { - return getState().isConferenceUserRoom(); - } - - /** - * Set this room as a conference user room - * - * @param isConferenceUserRoom true when it is an user conference room. - */ - public void setIsConferenceUserRoom(boolean isConferenceUserRoom) { - getState().setIsConferenceUserRoom(isConferenceUserRoom); - } - - /** - * Test if there is an ongoing conference call. - * - * @return true if there is one. - */ - public boolean isOngoingConferenceCall() { - RoomMember conferenceUser = getState().getMember(MXCallsManager.getConferenceUserId(getRoomId())); - return (null != conferenceUser) && TextUtils.equals(conferenceUser.membership, RoomMember.MEMBERSHIP_JOIN); - } - - /** - * Defines that the current room is a left one - * - * @param isLeft true when the current room is a left one - */ - public void setIsLeft(boolean isLeft) { - mIsLeft = isLeft; - mTimeline.setIsHistorical(isLeft); - } - - /** - * @return true if the current room is an left one - */ - public boolean isLeft() { - return mIsLeft; - } - - //================================================================================ - // Sync events - //================================================================================ - - /** - * Manage list of ephemeral events - * - * @param events the ephemeral events - */ - private void handleEphemeralEvents(List events) { - for (Event event : events) { - - // ensure that the room Id is defined - event.roomId = getRoomId(); - - try { - if (Event.EVENT_TYPE_RECEIPT.equals(event.getType())) { - if (event.roomId != null) { - List senders = handleReceiptEvent(event); - - if (senders != null && !senders.isEmpty()) { - mDataHandler.onReceiptEvent(event.roomId, senders); - } - } - } else if (Event.EVENT_TYPE_TYPING.equals(event.getType())) { - JsonObject eventContent = event.getContentAsJsonObject(); - - if (eventContent.has("user_ids")) { - synchronized (mTypingUsers) { - mTypingUsers.clear(); - - List typingUsers = null; - - try { - typingUsers = (new Gson()).fromJson(eventContent.get("user_ids"), new TypeToken>() { - }.getType()); - } catch (Exception e) { - Log.e(LOG_TAG, "## handleEphemeralEvents() : exception " + e.getMessage(), e); - } - - if (typingUsers != null) { - mTypingUsers.addAll(typingUsers); - } - } - } - - mDataHandler.onLiveEvent(event, getState()); - } - } catch (Exception e) { - Log.e(LOG_TAG, "ephemeral event failed " + e.getMessage(), e); - } - } - } - - /** - * Handle the events of a joined room. - * - * @param roomSync the sync events list. - * @param isGlobalInitialSync true if the room is initialized by a global initial sync. - */ - public void handleJoinedRoomSync(RoomSync roomSync, boolean isGlobalInitialSync) { - if (null != mOnInitialSyncCallback) { - Log.d(LOG_TAG, "initial sync handleJoinedRoomSync " + getRoomId()); - } else { - Log.d(LOG_TAG, "handleJoinedRoomSync " + getRoomId()); - } - - mIsSyncing = true; - - synchronized (this) { - mTimeline.handleJoinedRoomSync(roomSync, isGlobalInitialSync); - RoomSummary roomSummary = getRoomSummary(); - if (roomSummary != null) { - roomSummary.setIsJoined(); - } - // ephemeral events - if ((null != roomSync.ephemeral) && (null != roomSync.ephemeral.events)) { - handleEphemeralEvents(roomSync.ephemeral.events); - } - - // Handle account data events (if any) - if ((null != roomSync.accountData) && (null != roomSync.accountData.events) && (roomSync.accountData.events.size() > 0)) { - if (isGlobalInitialSync) { - Log.d(LOG_TAG, "## handleJoinedRoomSync : received " + roomSync.accountData.events.size() + " account data events"); - } - - handleAccountDataEvents(roomSync.accountData.events); - } - } - - // the user joined the room - // With V2 sync, the server sends the events to init the room. - if ((null != mOnInitialSyncCallback) && isJoined()) { - Log.d(LOG_TAG, "handleJoinedRoomSync " + getRoomId() + " : the initial sync is done"); - final ApiCallback fOnInitialSyncCallback = mOnInitialSyncCallback; - - new Handler(Looper.getMainLooper()).post(new Runnable() { - @Override - public void run() { - // to initialise the notification counters - markAllAsRead(null); - - try { - fOnInitialSyncCallback.onSuccess(null); - } catch (Exception e) { - Log.e(LOG_TAG, "handleJoinedRoomSync : onSuccess failed" + e.getMessage(), e); - } - } - }); - - mOnInitialSyncCallback = null; - } - - mIsSyncing = false; - - if (mRefreshUnreadAfterSync) { - if (!isGlobalInitialSync) { - refreshUnreadCounter(); - } // else -> it will be done at the end of the sync - mRefreshUnreadAfterSync = false; - } - } - - /** - * Handle the invitation room events - * - * @param invitedRoomSync the invitation room events. - */ - public void handleInvitedRoomSync(InvitedRoomSync invitedRoomSync) { - mTimeline.handleInvitedRoomSync(invitedRoomSync); - - RoomSummary roomSummary = getRoomSummary(); - - if (roomSummary != null) { - roomSummary.setIsInvited(); - } - } - - /** - * Store an outgoing event. - * - * @param event the event. - */ - public void storeOutgoingEvent(Event event) { - mTimeline.storeOutgoingEvent(event); - } - - /** - * Request events to the server. The local cache is not used. - * The events will not be saved in the local storage. - * - * @param token the token to go back from. - * @param paginationCount the number of events to retrieve. - * @param callback the onComplete callback - */ - public void requestServerRoomHistory(final String token, - final int paginationCount, - final ApiCallback callback) { - mDataHandler.getDataRetriever() - .requestServerRoomHistory(getRoomId(), token, paginationCount, mDataHandler.isLazyLoadingEnabled(), - new SimpleApiCallback(callback) { - @Override - public void onSuccess(TokensChunkEvents info) { - callback.onSuccess(info); - } - }); - } - - /** - * cancel any remote request - */ - public void cancelRemoteHistoryRequest() { - mDataHandler.getDataRetriever().cancelRemoteHistoryRequest(getRoomId()); - } - - //================================================================================ - // Getters / setters - //================================================================================ - - public String getRoomId() { - return getState().roomId; - } - - public void setAccountData(RoomAccountData accountData) { - mAccountData = accountData; - } - - public RoomAccountData getAccountData() { - return mAccountData; - } - - public RoomState getState() { - return mTimeline.getState(); - } - - public boolean isLeaving() { - return mIsLeaving; - } - - public void getMembersAsync(@NonNull final ApiCallback> callback) { - getState().getMembersAsync(callback); - } - - public void getDisplayableMembersAsync(@NonNull final ApiCallback> callback) { - getState().getDisplayableMembersAsync(callback); - } - - public EventTimeline getTimeline() { - return mTimeline; - } - - public void setTimeline(EventTimeline eventTimeline) { - mTimeline = eventTimeline; - } - - public void setReadyState(boolean isReady) { - mIsReady = isReady; - } - - public boolean isReady() { - return mIsReady; - } - - /** - * @return the list of active members in a room ie joined or invited ones. - */ - public void getActiveMembersAsync(@NonNull final ApiCallback> callback) { - getMembersAsync(new SimpleApiCallback>(callback) { - @Override - public void onSuccess(List members) { - List activeMembers = new ArrayList<>(); - String conferenceUserId = MXCallsManager.getConferenceUserId(getRoomId()); - - for (RoomMember member : members) { - if (!TextUtils.equals(member.getUserId(), conferenceUserId)) { - if (TextUtils.equals(member.membership, RoomMember.MEMBERSHIP_JOIN) - || TextUtils.equals(member.membership, RoomMember.MEMBERSHIP_INVITE)) { - activeMembers.add(member); - } - } - } - - callback.onSuccess(activeMembers); - } - }); - } - - /** - * Get the list of the members who have joined the room. - * - * @return the list the joined members of the room. - */ - public void getJoinedMembersAsync(final ApiCallback> callback) { - getMembersAsync(new SimpleApiCallback>(callback) { - @Override - public void onSuccess(List members) { - List joinedMembersList = new ArrayList<>(); - - for (RoomMember member : members) { - if (TextUtils.equals(member.membership, RoomMember.MEMBERSHIP_JOIN)) { - joinedMembersList.add(member); - } - } - - callback.onSuccess(joinedMembersList); - } - }); - } - - @Nullable - public RoomMember getMember(String userId) { - return getState().getMember(userId); - } - - // member event caches - private final Map mMemberEventByEventId = new HashMap<>(); - - public void getMemberEvent(final String userId, final ApiCallback callback) { - final Event event; - final RoomMember member = getMember(userId); - - if ((null != member) && (null != member.getOriginalEventId())) { - event = mMemberEventByEventId.get(member.getOriginalEventId()); - - if (null == event) { - mDataHandler.getDataRetriever().getRoomsRestClient().getEvent(getRoomId(), member.getOriginalEventId(), new SimpleApiCallback(callback) { - @Override - public void onSuccess(Event event) { - if (null != event) { - mMemberEventByEventId.put(event.eventId, event); - } - callback.onSuccess(event); - } - }); - return; - } - } else { - event = null; - } - - new Handler(Looper.getMainLooper()).post(new Runnable() { - @Override - public void run() { - callback.onSuccess(event); - } - }); - } - - public String getTopic() { - return getState().topic; - } - - public String getVisibility() { - return getState().visibility; - } - - /** - * @return true if the user is invited to the room - */ - public boolean isInvited() { - if (getRoomSummary() == null) { - return false; - } - - return getRoomSummary().isInvited(); - } - - /** - * @return true if the user has joined the room - */ - public boolean isJoined() { - if (getRoomSummary() == null) { - return false; - } - - return getRoomSummary().isJoined(); - } - - /** - * @return true is the user is a member of the room (invited or joined) - */ - public boolean isMember() { - return isJoined() || isInvited(); - } - - /** - * @return true if the user is invited in a direct chat room - */ - public boolean isDirectChatInvitation() { - if (isInvited()) { - // Is it an initial sync for this room ? - RoomState state = getState(); - - RoomMember selfMember = state.getMember(mMyUserId); - - if ((null != selfMember) && (null != selfMember.isDirect)) { - return selfMember.isDirect; - } - } - - return false; - } - - //================================================================================ - // Join - //================================================================================ - - /** - * Defines the initial sync callback - * - * @param callback the new callback. - */ - public void setOnInitialSyncCallback(ApiCallback callback) { - mOnInitialSyncCallback = callback; - } - - /** - * Join a room with an url to post before joined the room. - * - * @param alias the room alias - * @param thirdPartySignedUrl the thirdPartySigned url - * @param callback the callback - */ - public void joinWithThirdPartySigned(final String alias, final String thirdPartySignedUrl, final ApiCallback callback) { - if (null == thirdPartySignedUrl) { - join(alias, callback); - } else { - String url = thirdPartySignedUrl + "&mxid=" + mMyUserId; - UrlPostTask task = new UrlPostTask(); - - task.setListener(new UrlPostTask.IPostTaskListener() { - @Override - public void onSucceed(JsonObject object) { - Map map = null; - - try { - map = new Gson().fromJson(object, new TypeToken>() { - }.getType()); - } catch (Exception e) { - Log.e(LOG_TAG, "joinWithThirdPartySigned : Gson().fromJson failed" + e.getMessage(), e); - } - - if (null != map) { - Map joinMap = new HashMap<>(); - joinMap.put("third_party_signed", map); - join(alias, joinMap, callback); - } else { - join(callback); - } - } - - @Override - public void onError(String errorMessage) { - Log.d(LOG_TAG, "joinWithThirdPartySigned failed " + errorMessage); - - // cannot validate the url - // try without validating the url - join(callback); - } - }); - - // avoid crash if there are too many running task - try { - task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, url); - } catch (final Exception e) { - task.cancel(true); - Log.e(LOG_TAG, "joinWithThirdPartySigned : task.executeOnExecutor failed" + e.getMessage(), e); - - (new android.os.Handler(Looper.getMainLooper())).post(new Runnable() { - @Override - public void run() { - if (null != callback) { - callback.onUnexpectedError(e); - } - } - }); - } - } - } - - /** - * Join the room. If successful, the room's current state will be loaded before calling back onComplete. - * - * @param callback the callback for when done - */ - public void join(final ApiCallback callback) { - join(null, null, callback); - } - - /** - * Join the room. If successful, the room's current state will be loaded before calling back onComplete. - * - * @param roomAlias the room alias - * @param callback the callback for when done - */ - private void join(String roomAlias, ApiCallback callback) { - join(roomAlias, null, callback); - } - - /** - * Join the room. If successful, the room's current state will be loaded before calling back onComplete. - * - * @param roomAlias the room alias - * @param extraParams the join extra params - * @param callback the callback for when done - */ - private void join(final String roomAlias, final Map extraParams, final ApiCallback callback) { - Log.d(LOG_TAG, "Join the room " + getRoomId() + " with alias " + roomAlias); - - mDataHandler.getDataRetriever().getRoomsRestClient() - .joinRoom((null != roomAlias) ? roomAlias : getRoomId(), extraParams, new SimpleApiCallback(callback) { - @Override - public void onSuccess(final RoomResponse aResponse) { - try { - // the join request did not get the room initial history - if (!isJoined()) { - Log.d(LOG_TAG, "the room " + getRoomId() + " is joined but wait after initial sync"); - - // wait the server sends the events chunk before calling the callback - setOnInitialSyncCallback(callback); - } else { - Log.d(LOG_TAG, "the room " + getRoomId() + " is joined : the initial sync has been done"); - // to initialise the notification counters - markAllAsRead(null); - // already got the initial sync - callback.onSuccess(null); - } - } catch (Exception e) { - Log.e(LOG_TAG, "join exception " + e.getMessage(), e); - } - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "join onNetworkError " + e.getMessage(), e); - callback.onNetworkError(e); - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "join onMatrixError " + e.getMessage()); - - if (MatrixError.UNKNOWN.equals(e.errcode) && TextUtils.equals("No known servers", e.error)) { - // minging kludge until https://matrix.org/jira/browse/SYN-678 is fixed - // 'Error when trying to join an empty room should be more explicit - e.error = getStore().getContext().getString(R.string.room_error_join_failed_empty_room); - } - - // if the alias is not found - // try with the room id - if ((e.mStatus == 404) && !TextUtils.isEmpty(roomAlias)) { - Log.e(LOG_TAG, "Retry without the room alias"); - join(null, extraParams, callback); - return; - } - - callback.onMatrixError(e); - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "join onUnexpectedError " + e.getMessage(), e); - callback.onUnexpectedError(e); - } - }); - } - - //================================================================================ - // Room info (liveState) update - //================================================================================ - - /** - * This class dispatches the error to the dedicated callbacks. - * If the operation succeeds, the room state is saved because calling the callback. - */ - private class RoomInfoUpdateCallback extends SimpleApiCallback { - private final ApiCallback mCallback; - - /** - * Constructor - */ - public RoomInfoUpdateCallback(ApiCallback callback) { - super(callback); - mCallback = callback; - } - - @Override - public void onSuccess(T info) { - getStore().storeLiveStateForRoom(getRoomId()); - - if (null != mCallback) { - mCallback.onSuccess(info); - } - } - } - - /** - * Update the power level of the user userId - * - * @param userId the user id - * @param powerLevel the new power level - * @param callback the callback with the created event - */ - public void updateUserPowerLevels(String userId, int powerLevel, ApiCallback callback) { - PowerLevels powerLevels = getState().getPowerLevels().deepCopy(); - powerLevels.setUserPowerLevel(userId, powerLevel); - mDataHandler.getDataRetriever().getRoomsRestClient().updatePowerLevels(getRoomId(), powerLevels, callback); - } - - /** - * Update the room's name. - * - * @param aRoomName the new name - * @param callback the async callback - */ - public void updateName(final String aRoomName, final ApiCallback callback) { - mDataHandler.getDataRetriever().getRoomsRestClient().updateRoomName(getRoomId(), aRoomName, new RoomInfoUpdateCallback(callback) { - @Override - public void onSuccess(Void info) { - getState().name = aRoomName; - super.onSuccess(info); - } - }); - } - - /** - * Update the room's topic. - * - * @param aTopic the new topic - * @param callback the async callback - */ - public void updateTopic(final String aTopic, final ApiCallback callback) { - mDataHandler.getDataRetriever().getRoomsRestClient().updateTopic(getRoomId(), aTopic, new RoomInfoUpdateCallback(callback) { - @Override - public void onSuccess(Void info) { - getState().topic = aTopic; - super.onSuccess(info); - } - }); - } - - /** - * Update the room's main alias. - * - * @param aCanonicalAlias the canonical alias - * @param callback the async callback - */ - public void updateCanonicalAlias(final String aCanonicalAlias, final ApiCallback callback) { - final String fCanonicalAlias = TextUtils.isEmpty(aCanonicalAlias) ? null : aCanonicalAlias; - - mDataHandler.getDataRetriever().getRoomsRestClient().updateCanonicalAlias(getRoomId(), fCanonicalAlias, new RoomInfoUpdateCallback(callback) { - @Override - public void onSuccess(Void info) { - getState().setCanonicalAlias(aCanonicalAlias); - super.onSuccess(info); - } - }); - } - - /** - * Provides the room aliases list. - * The result is never null. - * - * @return the room aliases list. - */ - public List getAliases() { - return getState().getAliases(); - } - - /** - * Remove a room alias. - * - * @param alias the alias to remove - * @param callback the async callback - */ - public void removeAlias(final String alias, final ApiCallback callback) { - final List updatedAliasesList = new ArrayList<>(getAliases()); - - // nothing to do - if (TextUtils.isEmpty(alias) || (updatedAliasesList.indexOf(alias) < 0)) { - if (null != callback) { - callback.onSuccess(null); - } - return; - } - - mDataHandler.getDataRetriever().getRoomsRestClient().removeRoomAlias(alias, new RoomInfoUpdateCallback(callback) { - @Override - public void onSuccess(Void info) { - getState().removeAlias(alias); - super.onSuccess(info); - } - }); - } - - /** - * Try to add an alias to the aliases list. - * - * @param alias the alias to add. - * @param callback the the async callback - */ - public void addAlias(final String alias, final ApiCallback callback) { - final List updatedAliasesList = new ArrayList<>(getAliases()); - - // nothing to do - if (TextUtils.isEmpty(alias) || (updatedAliasesList.indexOf(alias) >= 0)) { - if (null != callback) { - callback.onSuccess(null); - } - return; - } - - mDataHandler.getDataRetriever().getRoomsRestClient().setRoomIdByAlias(getRoomId(), alias, new RoomInfoUpdateCallback(callback) { - @Override - public void onSuccess(Void info) { - getState().addAlias(alias); - super.onSuccess(info); - } - }); - } - - /** - * Add a group to the related ones - * - * @param groupId the group id to add - * @param callback the asynchronous callback - */ - public void addRelatedGroup(final String groupId, final ApiCallback callback) { - List nextGroupIdsList = new ArrayList<>(getState().getRelatedGroups()); - - if (!nextGroupIdsList.contains(groupId)) { - nextGroupIdsList.add(groupId); - } - - updateRelatedGroups(nextGroupIdsList, callback); - } - - /** - * Remove a group id from the related ones. - * - * @param groupId the group id - * @param callback the asynchronous callback - */ - public void removeRelatedGroup(final String groupId, final ApiCallback callback) { - List nextGroupIdsList = new ArrayList<>(getState().getRelatedGroups()); - nextGroupIdsList.remove(groupId); - - updateRelatedGroups(nextGroupIdsList, callback); - } - - /** - * Update the related group ids list - * - * @param groupIds the new related groups - * @param callback the asynchronous callback - */ - public void updateRelatedGroups(final List groupIds, final ApiCallback callback) { - Map params = new HashMap<>(); - params.put("groups", groupIds); - - mDataHandler.getDataRetriever().getRoomsRestClient() - .sendStateEvent(getRoomId(), Event.EVENT_TYPE_STATE_RELATED_GROUPS, null, params, new SimpleApiCallback(callback) { - @Override - public void onSuccess(Void info) { - getState().groups = groupIds; - getDataHandler().getStore().storeLiveStateForRoom(getRoomId()); - - if (null != callback) { - callback.onSuccess(null); - } - } - }); - } - - - /** - * @return the room avatar URL. If there is no defined one, use the members one (1:1 chat only). - */ - @Nullable - public String getAvatarUrl() { - String res = getState().getAvatarUrl(); - - // detect if it is a room with no more than 2 members (i.e. an alone or a 1:1 chat) - if (null == res) { - if (getNumberOfMembers() == 1 && !getState().getLoadedMembers().isEmpty()) { - res = getState().getLoadedMembers().get(0).getAvatarUrl(); - } else if (getNumberOfMembers() == 2 && getState().getLoadedMembers().size() > 1) { - RoomMember m1 = getState().getLoadedMembers().get(0); - RoomMember m2 = getState().getLoadedMembers().get(1); - - res = TextUtils.equals(m1.getUserId(), mMyUserId) ? m2.getAvatarUrl() : m1.getAvatarUrl(); - } - } - - return res; - } - - /** - * The call avatar is the same as the room avatar except there are only 2 JOINED members. - * In this case, it returns the avtar of the other joined member. - * - * @return the call avatar URL. - */ - @Nullable - public String getCallAvatarUrl() { - String avatarURL; - - if (getNumberOfMembers() == 2 && getState().getLoadedMembers().size() > 1) { - RoomMember m1 = getState().getLoadedMembers().get(0); - RoomMember m2 = getState().getLoadedMembers().get(1); - - // use other member avatar. - if (TextUtils.equals(mMyUserId, m1.getUserId())) { - avatarURL = m2.getAvatarUrl(); - } else { - avatarURL = m1.getAvatarUrl(); - } - } else { - // - avatarURL = getAvatarUrl(); - } - - return avatarURL; - } - - /** - * Update the room avatar URL. - * - * @param avatarUrl the new avatar URL - * @param callback the async callback - */ - public void updateAvatarUrl(final String avatarUrl, final ApiCallback callback) { - mDataHandler.getDataRetriever().getRoomsRestClient().updateAvatarUrl(getRoomId(), avatarUrl, new RoomInfoUpdateCallback(callback) { - @Override - public void onSuccess(Void info) { - getState().url = avatarUrl; - super.onSuccess(info); - } - }); - } - - /** - * Update the room's history visibility - * - * @param historyVisibility the visibility (should be one of RoomState.HISTORY_VISIBILITY_XX values) - * @param callback the async callback - */ - public void updateHistoryVisibility(final String historyVisibility, final ApiCallback callback) { - mDataHandler.getDataRetriever().getRoomsRestClient() - .updateHistoryVisibility(getRoomId(), historyVisibility, new RoomInfoUpdateCallback(callback) { - @Override - public void onSuccess(Void info) { - getState().history_visibility = historyVisibility; - super.onSuccess(info); - } - }); - } - - /** - * Update the directory's visibility - * - * @param visibility the visibility (should be one of RoomState.HISTORY_VISIBILITY_XX values) - * @param callback the async callback - */ - public void updateDirectoryVisibility(final String visibility, final ApiCallback callback) { - mDataHandler.getDataRetriever().getRoomsRestClient().updateDirectoryVisibility(getRoomId(), visibility, new RoomInfoUpdateCallback(callback) { - @Override - public void onSuccess(Void info) { - getState().visibility = visibility; - super.onSuccess(info); - } - }); - } - - /** - * Get the directory visibility of the room (see {@link #updateDirectoryVisibility(String, ApiCallback)}). - * The directory visibility indicates if the room is listed among the directory list. - * - * @param roomId the user Id. - * @param callback the callback returning the visibility response value. - */ - public void getDirectoryVisibility(final String roomId, final ApiCallback callback) { - RoomsRestClient roomRestApi = mDataHandler.getDataRetriever().getRoomsRestClient(); - - if (null != roomRestApi) { - roomRestApi.getDirectoryVisibility(roomId, new SimpleApiCallback(callback) { - @Override - public void onSuccess(RoomDirectoryVisibility roomDirectoryVisibility) { - RoomState currentRoomState = getState(); - if (null != currentRoomState) { - currentRoomState.visibility = roomDirectoryVisibility.visibility; - } - - if (null != callback) { - callback.onSuccess(roomDirectoryVisibility.visibility); - } - } - }); - } - } - - /** - * Update the join rule of the room. - * - * @param aRule the join rule: {@link RoomState#JOIN_RULE_PUBLIC} or {@link RoomState#JOIN_RULE_INVITE} - * @param aCallBackResp the async callback - */ - public void updateJoinRules(final String aRule, final ApiCallback aCallBackResp) { - mDataHandler.getDataRetriever().getRoomsRestClient().updateJoinRules(getRoomId(), aRule, new RoomInfoUpdateCallback(aCallBackResp) { - @Override - public void onSuccess(Void info) { - getState().join_rule = aRule; - super.onSuccess(info); - } - }); - } - - /** - * Update the guest access rule of the room. - * To deny guest access to the room, aGuestAccessRule must be set to {@link RoomState#GUEST_ACCESS_FORBIDDEN}. - * - * @param aGuestAccessRule the guest access rule: {@link RoomState#GUEST_ACCESS_CAN_JOIN} or {@link RoomState#GUEST_ACCESS_FORBIDDEN} - * @param callback the async callback - */ - public void updateGuestAccess(final String aGuestAccessRule, final ApiCallback callback) { - mDataHandler.getDataRetriever().getRoomsRestClient().updateGuestAccess(getRoomId(), aGuestAccessRule, new RoomInfoUpdateCallback(callback) { - @Override - public void onSuccess(Void info) { - getState().guest_access = aGuestAccessRule; - super.onSuccess(info); - } - }); - } - - //================================================================================ - // Read receipts events - //================================================================================ - - /** - * @return the call conference user id - */ - private String getCallConferenceUserId() { - if (null == mCallConferenceUserId) { - mCallConferenceUserId = MXCallsManager.getConferenceUserId(getRoomId()); - } - - return mCallConferenceUserId; - } - - /** - * Handle a receiptData. - * - * @param receiptData the receiptData. - * @return true if there a store update. - */ - public boolean handleReceiptData(ReceiptData receiptData) { - if (!TextUtils.equals(receiptData.userId, getCallConferenceUserId()) && (null != getStore())) { - boolean isUpdated = getStore().storeReceipt(receiptData, getRoomId()); - - // check oneself receipts - // if there is an update, it means that the messages have been read from another client - // it requires to update the summary to display valid information. - if (isUpdated && TextUtils.equals(mMyUserId, receiptData.userId)) { - RoomSummary summary = getStore().getSummary(getRoomId()); - - if (null != summary) { - summary.setReadReceiptEventId(receiptData.eventId); - getStore().flushSummary(summary); - } - - refreshUnreadCounter(); - } - - return isUpdated; - } else { - return false; - } - } - - /** - * Handle receipt event. - * Event content will contains the receipts dictionaries - *

-     * key   : $EventId
-     * value : dict key @UserId
-     *              value dict key "ts"
-     *                    dict value ts value
-     * 
- *

- * Example: - *

-     * {
-     *     "$1535657109773196ZjoWE:matrix.org": {
-     *         "m.read": {
-     *             "@slash_benoit:matrix.org": {
-     *                 "ts": 1535708570621
-     *             },
-     *             "@benoit.marty:matrix.org": {
-     *                 "ts": 1535657109472
-     *             }
-     *         }
-     *     }
-     * },
-     * 
- * - * @param event the event receipts. - * @return the sender user IDs list. - */ - private List handleReceiptEvent(Event event) { - List senderIDs = new ArrayList<>(); - - try { - Type type = new TypeToken>>>>() { - }.getType(); - Map>>> receiptsDict = JsonUtils.getGson(false).fromJson(event.getContent(), type); - - for (String eventId : receiptsDict.keySet()) { - Map>> receiptDict = receiptsDict.get(eventId); - - for (String receiptType : receiptDict.keySet()) { - // only the read receipts are managed - if (TextUtils.equals(receiptType, "m.read")) { - Map> userIdsDict = receiptDict.get(receiptType); - - for (String userID : userIdsDict.keySet()) { - Map paramsDict = userIdsDict.get(userID); - - for (String paramName : paramsDict.keySet()) { - if (TextUtils.equals("ts", paramName)) { - Double value = (Double) paramsDict.get(paramName); - long ts = value.longValue(); - - if (handleReceiptData(new ReceiptData(userID, eventId, ts))) { - senderIDs.add(userID); - } - } - } - } - } - } - } - } catch (Exception e) { - Log.e(LOG_TAG, "handleReceiptEvent : failed" + e.getMessage(), e); - } - - return senderIDs; - } - - /** - * Clear the unread message counters - * - * @param summary the room summary - */ - private void clearUnreadCounters(RoomSummary summary) { - Log.d(LOG_TAG, "## clearUnreadCounters " + getRoomId()); - - // reset the notification count - getState().setHighlightCount(0); - getState().setNotificationCount(0); - - if (null != getStore()) { - getStore().storeLiveStateForRoom(getRoomId()); - - // flush the summary - if (null != summary) { - summary.setUnreadEventsCount(0); - summary.setHighlightCount(0); - summary.setNotificationCount(0); - getStore().flushSummary(summary); - } - - getStore().commit(); - } - } - - /** - * @return the read marker event id - */ - public String getReadMarkerEventId() { - if (null == getStore()) { - return null; - } - - RoomSummary summary = getStore().getSummary(getRoomId()); - - if (null != summary) { - return (null != summary.getReadMarkerEventId()) ? summary.getReadMarkerEventId() : summary.getReadReceiptEventId(); - } else { - return null; - } - } - - /** - * Mark all the messages as read. - * It also move the read marker to the latest known messages - * - * @param aRespCallback the asynchronous callback - * @return true if the request is sent, false otherwise - */ - public boolean markAllAsRead(final ApiCallback aRespCallback) { - return markAllAsRead(true, aRespCallback); - } - - /** - * Mark all the messages as read. - * It also move the read marker to the latest known messages if updateReadMarker is set to true - * - * @param updateReadMarker true to move the read marker to the latest known event - * @param aRespCallback the asynchronous callback - * @return true if the request is sent, false otherwise - */ - private boolean markAllAsRead(boolean updateReadMarker, final ApiCallback aRespCallback) { - final Event lastEvent = (null != getStore()) ? getStore().getLatestEvent(getRoomId()) : null; - boolean res = sendReadMarkers(updateReadMarker ? ((null != lastEvent) ? lastEvent.eventId : null) : getReadMarkerEventId(), null, aRespCallback); - - if (!res) { - RoomSummary summary = (null != getStore()) ? getStore().getSummary(getRoomId()) : null; - - if (null != summary) { - if ((0 != summary.getUnreadEventsCount()) - || (0 != summary.getHighlightCount()) - || (0 != summary.getNotificationCount())) { - Log.e(LOG_TAG, "## markAllAsRead() : the summary events counters should be cleared for " + getRoomId()); - - Event latestEvent = getStore().getLatestEvent(getRoomId()); - summary.setLatestReceivedEvent(latestEvent); - - if (null != latestEvent) { - summary.setReadReceiptEventId(latestEvent.eventId); - } else { - summary.setReadReceiptEventId(null); - } - - summary.setUnreadEventsCount(0); - summary.setHighlightCount(0); - summary.setNotificationCount(0); - getStore().flushSummary(summary); - } - } else { - Log.e(LOG_TAG, "## sendReadReceipt() : no summary for " + getRoomId()); - } - - if ((0 != getState().getNotificationCount()) || (0 != getState().getHighlightCount())) { - Log.e(LOG_TAG, "## markAllAsRead() : the notification messages count for " + getRoomId() + " should have been cleared"); - - getState().setNotificationCount(0); - getState().setHighlightCount(0); - - if (null != getStore()) { - getStore().storeLiveStateForRoom(getRoomId()); - } - } - } - - return res; - } - - /** - * Update the read marker event Id - * - * @param readMarkerEventId the read marker even id - */ - public void setReadMakerEventId(final String readMarkerEventId) { - RoomSummary summary = (null != getStore()) ? getStore().getSummary(getRoomId()) : null; - if (summary != null && !readMarkerEventId.equals(summary.getReadMarkerEventId())) { - sendReadMarkers(readMarkerEventId, summary.getReadReceiptEventId(), null); - } - } - - /** - * Send a read receipt to the latest known event - */ - public void sendReadReceipt() { - markAllAsRead(false, null); - } - - /** - * Send the read receipt to the latest room message id. - * - * @param event send a read receipt to a provided event - * @param aRespCallback asynchronous response callback - * @return true if the read receipt has been sent, false otherwise - */ - public boolean sendReadReceipt(Event event, final ApiCallback aRespCallback) { - String eventId = (null != event) ? event.eventId : null; - Log.d(LOG_TAG, "## sendReadReceipt() : eventId " + eventId + " in room " + getRoomId()); - return sendReadMarkers(null, eventId, aRespCallback); - } - - /** - * Forget the current read marker - * This will update the read marker to match the read receipt - * - * @param callback the asynchronous callback - */ - public void forgetReadMarker(final ApiCallback callback) { - final RoomSummary summary = (null != getStore()) ? getStore().getSummary(getRoomId()) : null; - final String currentReadReceipt = (null != summary) ? summary.getReadReceiptEventId() : null; - - if (null != summary) { - Log.d(LOG_TAG, "## forgetReadMarker() : update the read marker to " + currentReadReceipt + " in room " + getRoomId()); - summary.setReadMarkerEventId(currentReadReceipt); - getStore().flushSummary(summary); - } - - setReadMarkers(currentReadReceipt, currentReadReceipt, callback); - } - - /** - * Send the read markers - * - * @param aReadMarkerEventId the new read marker event id (if null use the latest known event id) - * @param aReadReceiptEventId the new read receipt event id (if null use the latest known event id) - * @param aRespCallback asynchronous response callback - * @return true if the request is sent, false otherwise - */ - public boolean sendReadMarkers(final String aReadMarkerEventId, final String aReadReceiptEventId, final ApiCallback aRespCallback) { - final Event lastEvent = (null != getStore()) ? getStore().getLatestEvent(getRoomId()) : null; - - // reported by GA - if (null == lastEvent) { - Log.e(LOG_TAG, "## sendReadMarkers(): no last event"); - return false; - } - - Log.d(LOG_TAG, "## sendReadMarkers(): readMarkerEventId " + aReadMarkerEventId + " readReceiptEventId " + aReadReceiptEventId - + " in room " + getRoomId()); - - boolean hasUpdate = false; - - String readMarkerEventId = aReadMarkerEventId; - if (!TextUtils.isEmpty(aReadMarkerEventId)) { - if (!MXPatterns.isEventId(aReadMarkerEventId)) { - Log.e(LOG_TAG, "## sendReadMarkers() : invalid event id " + readMarkerEventId); - // Read marker is invalid, ignore it - readMarkerEventId = null; - } else { - // Check if the read marker is updated - RoomSummary summary = getStore().getSummary(getRoomId()); - if ((null != summary) && !TextUtils.equals(readMarkerEventId, summary.getReadMarkerEventId())) { - // Make sure the new read marker event is newer than the current one - final Event newReadMarkerEvent = getStore().getEvent(readMarkerEventId, getRoomId()); - final Event currentReadMarkerEvent = getStore().getEvent(summary.getReadMarkerEventId(), getRoomId()); - if (newReadMarkerEvent == null || currentReadMarkerEvent == null - || newReadMarkerEvent.getOriginServerTs() > currentReadMarkerEvent.getOriginServerTs()) { - // Event is not in store (assume it is in the past), or is older than current one - Log.d(LOG_TAG, "## sendReadMarkers(): set new read marker event id " + readMarkerEventId + " in room " + getRoomId()); - summary.setReadMarkerEventId(readMarkerEventId); - getStore().flushSummary(summary); - hasUpdate = true; - } - } - } - } - - final String readReceiptEventId = (null == aReadReceiptEventId) ? lastEvent.eventId : aReadReceiptEventId; - // check if the read receipt event id is already read - if ((null != getStore()) && !getStore().isEventRead(getRoomId(), getDataHandler().getUserId(), readReceiptEventId)) { - // check if the event id update is allowed - if (handleReceiptData(new ReceiptData(mMyUserId, readReceiptEventId, System.currentTimeMillis()))) { - // Clear the unread counters if the latest message is displayed - // We don't try to compute the unread counters for oldest messages : - // ---> it would require too much time. - // The counters are cleared to avoid displaying invalid values - // when the device is offline. - // The read receipts will be sent later - // (asap there is a valid network connection) - if (TextUtils.equals(lastEvent.eventId, readReceiptEventId)) { - clearUnreadCounters(getStore().getSummary(getRoomId())); - } - hasUpdate = true; - } - } - - if (hasUpdate) { - setReadMarkers(readMarkerEventId, readReceiptEventId, aRespCallback); - } - - return hasUpdate; - } - - /** - * Send the request to update the read marker and read receipt. - * - * @param aReadMarkerEventId the read marker event id - * @param aReadReceiptEventId the read receipt event id - * @param callback the asynchronous callback - */ - private void setReadMarkers(final String aReadMarkerEventId, final String aReadReceiptEventId, final ApiCallback callback) { - Log.d(LOG_TAG, "## setReadMarkers(): readMarkerEventId " + aReadMarkerEventId + " readReceiptEventId " + aReadMarkerEventId); - - // check if the message ids are valid - final String readMarkerEventId = MXPatterns.isEventId(aReadMarkerEventId) ? aReadMarkerEventId : null; - final String readReceiptEventId = MXPatterns.isEventId(aReadReceiptEventId) ? aReadReceiptEventId : null; - - // if there is nothing to do - if (TextUtils.isEmpty(readMarkerEventId) && TextUtils.isEmpty(readReceiptEventId)) { - new Handler(Looper.getMainLooper()).post(new Runnable() { - @Override - public void run() { - if (null != callback) { - callback.onSuccess(null); - } - } - }); - } else { - mDataHandler.getDataRetriever().getRoomsRestClient().sendReadMarker(getRoomId(), readMarkerEventId, readReceiptEventId, - new SimpleApiCallback(callback) { - @Override - public void onSuccess(Void info) { - if (null != callback) { - callback.onSuccess(info); - } - } - }); - } - } - - /** - * Check if an event has been read. - * - * @param eventId the event id - * @return true if the message has been read - */ - public boolean isEventRead(String eventId) { - if (null != getStore()) { - return getStore().isEventRead(getRoomId(), mMyUserId, eventId); - } else { - return false; - } - } - - //================================================================================ - // Unread event count management - //================================================================================ - - /** - * @return the number of unread messages that match the push notification rules. - */ - public int getNotificationCount() { - return getState().getNotificationCount(); - } - - /** - * @return the number of highlighted events. - */ - public int getHighlightCount() { - return getState().getHighlightCount(); - } - - /** - * refresh the unread events counts. - */ - public void refreshUnreadCounter() { - // avoid refreshing the unread counter while processing a bunch of messages. - if (!mIsSyncing) { - RoomSummary summary = (null != getStore()) ? getStore().getSummary(getRoomId()) : null; - - if (null != summary) { - int prevValue = summary.getUnreadEventsCount(); - int newValue = getStore().eventsCountAfter(getRoomId(), summary.getReadReceiptEventId()); - - if (prevValue != newValue) { - summary.setUnreadEventsCount(newValue); - getStore().flushSummary(summary); - } - } - } else { - // wait the sync end before computing is again - mRefreshUnreadAfterSync = true; - } - } - - //================================================================================ - // typing events - //================================================================================ - - // userIds list - @NonNull - private final List mTypingUsers = new ArrayList<>(); - - /** - * Get typing users - * - * @return the userIds list - */ - @NonNull - public List getTypingUsers() { - List typingUsers; - - synchronized (mTypingUsers) { - typingUsers = new ArrayList<>(mTypingUsers); - } - - return typingUsers; - } - - /** - * Send a typing notification - * - * @param isTyping typing status - * @param timeout the typing timeout - * @param callback asynchronous callback - */ - public void sendTypingNotification(boolean isTyping, int timeout, ApiCallback callback) { - // send the event only if the user has joined the room. - if (isJoined()) { - mDataHandler.getDataRetriever().getRoomsRestClient().sendTypingNotification(getRoomId(), mMyUserId, isTyping, timeout, callback); - } - } - - //================================================================================ - // Medias events - //================================================================================ - - /** - * Fill the locationInfo - * - * @param context the context - * @param locationMessage the location message - * @param thumbnailUri the thumbnail uri - * @param thumbMimeType the thumbnail mime type - */ - public static void fillLocationInfo(Context context, LocationMessage locationMessage, Uri thumbnailUri, String thumbMimeType) { - if (null != thumbnailUri) { - try { - locationMessage.thumbnail_url = thumbnailUri.toString(); - - ThumbnailInfo thumbInfo = new ThumbnailInfo(); - File thumbnailFile = new File(thumbnailUri.getPath()); - - ExifInterface exifMedia = new ExifInterface(thumbnailUri.getPath()); - String sWidth = exifMedia.getAttribute(ExifInterface.TAG_IMAGE_WIDTH); - String sHeight = exifMedia.getAttribute(ExifInterface.TAG_IMAGE_LENGTH); - - if (null != sWidth) { - thumbInfo.w = Integer.parseInt(sWidth); - } - - if (null != sHeight) { - thumbInfo.h = Integer.parseInt(sHeight); - } - - thumbInfo.size = Long.valueOf(thumbnailFile.length()); - thumbInfo.mimetype = thumbMimeType; - locationMessage.thumbnail_info = thumbInfo; - } catch (Exception e) { - Log.e(LOG_TAG, "fillLocationInfo : failed" + e.getMessage(), e); - } - } - } - - /** - * Fills the VideoMessage info. - * - * @param context Application context for the content resolver. - * @param videoMessage The VideoMessage to fill. - * @param fileUri The file uri. - * @param videoMimeType The mimeType - * @param thumbnailUri the thumbnail uri - * @param thumbMimeType the thumbnail mime type - */ - public static void fillVideoInfo(Context context, VideoMessage videoMessage, Uri fileUri, String videoMimeType, Uri thumbnailUri, String thumbMimeType) { - try { - VideoInfo videoInfo = new VideoInfo(); - File file = new File(fileUri.getPath()); - - MediaMetadataRetriever retriever = new MediaMetadataRetriever(); - retriever.setDataSource(file.getAbsolutePath()); - - Bitmap bmp = retriever.getFrameAtTime(); - videoInfo.h = bmp.getHeight(); - videoInfo.w = bmp.getWidth(); - videoInfo.mimetype = videoMimeType; - - try { - MediaPlayer mp = MediaPlayer.create(context, fileUri); - if (null != mp) { - videoInfo.duration = Long.valueOf(mp.getDuration()); - mp.release(); - } - } catch (Exception e) { - Log.e(LOG_TAG, "fillVideoInfo : MediaPlayer.create failed" + e.getMessage(), e); - } - videoInfo.size = file.length(); - - // thumbnail - if (null != thumbnailUri) { - videoInfo.thumbnail_url = thumbnailUri.toString(); - - ThumbnailInfo thumbInfo = new ThumbnailInfo(); - File thumbnailFile = new File(thumbnailUri.getPath()); - - ExifInterface exifMedia = new ExifInterface(thumbnailUri.getPath()); - String sWidth = exifMedia.getAttribute(ExifInterface.TAG_IMAGE_WIDTH); - String sHeight = exifMedia.getAttribute(ExifInterface.TAG_IMAGE_LENGTH); - - if (null != sWidth) { - thumbInfo.w = Integer.parseInt(sWidth); - } - - if (null != sHeight) { - thumbInfo.h = Integer.parseInt(sHeight); - } - - thumbInfo.size = Long.valueOf(thumbnailFile.length()); - thumbInfo.mimetype = thumbMimeType; - videoInfo.thumbnail_info = thumbInfo; - } - - videoMessage.info = videoInfo; - } catch (Exception e) { - Log.e(LOG_TAG, "fillVideoInfo : failed" + e.getMessage(), e); - } - } - - /** - * Fills the fileMessage fileInfo. - * - * @param context Application context for the content resolver. - * @param fileMessage The fileMessage to fill. - * @param fileUri The file uri. - * @param mimeType The mimeType - */ - public static void fillFileInfo(Context context, FileMessage fileMessage, Uri fileUri, String mimeType) { - try { - FileInfo fileInfo = new FileInfo(); - - String filename = fileUri.getPath(); - File file = new File(filename); - - fileInfo.mimetype = mimeType; - fileInfo.size = file.length(); - - fileMessage.info = fileInfo; - - } catch (Exception e) { - Log.e(LOG_TAG, "fillFileInfo : failed" + e.getMessage(), e); - } - } - - - /** - * Update or create an ImageInfo for an image uri. - * - * @param context Application context for the content resolver. - * @param anImageInfo the imageInfo to fill, null to create a new one - * @param imageUri The full size image uri. - * @param mimeType The image mimeType - * @return the filled image info - */ - public static ImageInfo getImageInfo(Context context, ImageInfo anImageInfo, Uri imageUri, String mimeType) { - ImageInfo imageInfo = (null == anImageInfo) ? new ImageInfo() : anImageInfo; - - try { - String filename = imageUri.getPath(); - File file = new File(filename); - - ExifInterface exifMedia = new ExifInterface(filename); - String sWidth = exifMedia.getAttribute(ExifInterface.TAG_IMAGE_WIDTH); - String sHeight = exifMedia.getAttribute(ExifInterface.TAG_IMAGE_LENGTH); - - // the image rotation is replaced by orientation - // imageInfo.rotation = ImageUtils.getRotationAngleForBitmap(context, imageUri); - imageInfo.orientation = ImageUtils.getOrientationForBitmap(context, imageUri); - - int width = 0; - int height = 0; - - // extract the Exif info - if ((null != sWidth) && (null != sHeight)) { - - if ((imageInfo.orientation == ExifInterface.ORIENTATION_TRANSPOSE) - || (imageInfo.orientation == ExifInterface.ORIENTATION_ROTATE_90) - || (imageInfo.orientation == ExifInterface.ORIENTATION_TRANSVERSE) - || (imageInfo.orientation == ExifInterface.ORIENTATION_ROTATE_270)) { - height = Integer.parseInt(sWidth); - width = Integer.parseInt(sHeight); - } else { - width = Integer.parseInt(sWidth); - height = Integer.parseInt(sHeight); - } - } - - // there is no exif info or the size is invalid - if ((0 == width) || (0 == height)) { - try { - BitmapFactory.Options opts = new BitmapFactory.Options(); - opts.inJustDecodeBounds = true; - BitmapFactory.decodeFile(imageUri.getPath(), opts); - - // don't need to load the bitmap in memory - if ((opts.outHeight > 0) && (opts.outWidth > 0)) { - width = opts.outWidth; - height = opts.outHeight; - } - - } catch (Exception e) { - Log.e(LOG_TAG, "fillImageInfo : failed" + e.getMessage(), e); - } catch (OutOfMemoryError oom) { - Log.e(LOG_TAG, "fillImageInfo : oom", oom); - } - } - - // valid image size ? - if ((0 != width) || (0 != height)) { - imageInfo.w = width; - imageInfo.h = height; - } - - imageInfo.mimetype = mimeType; - imageInfo.size = file.length(); - } catch (Exception e) { - Log.e(LOG_TAG, "fillImageInfo : failed" + e.getMessage(), e); - imageInfo = null; - } - - return imageInfo; - } - - /** - * Fills the imageMessage imageInfo. - * - * @param context Application context for the content resolver. - * @param imageMessage The imageMessage to fill. - * @param imageUri The full size image uri. - * @param mimeType The image mimeType - */ - public static void fillImageInfo(Context context, ImageMessage imageMessage, Uri imageUri, String mimeType) { - imageMessage.info = getImageInfo(context, imageMessage.info, imageUri, mimeType); - } - - /** - * Fills the imageMessage imageInfo. - * - * @param context Application context for the content resolver. - * @param imageMessage The imageMessage to fill. - * @param thumbUri The thumbnail uri - * @param mimeType The image mimeType - */ - public static void fillThumbnailInfo(Context context, ImageMessage imageMessage, Uri thumbUri, String mimeType) { - ImageInfo imageInfo = getImageInfo(context, null, thumbUri, mimeType); - - if (null != imageInfo) { - if (null == imageMessage.info) { - imageMessage.info = new ImageInfo(); - } - - imageMessage.info.thumbnailInfo = new ThumbnailInfo(); - imageMessage.info.thumbnailInfo.w = imageInfo.w; - imageMessage.info.thumbnailInfo.h = imageInfo.h; - imageMessage.info.thumbnailInfo.size = imageInfo.size; - imageMessage.info.thumbnailInfo.mimetype = imageInfo.mimetype; - } - } - - //================================================================================ - // Call - //================================================================================ - - /** - * Test if a call can be performed in this room. - * - * @return true if a call can be performed. - */ - public boolean canPerformCall() { - return getNumberOfMembers() > 1; - } - - /** - * @return a list of callable members. - */ - public void callees(final ApiCallback> callback) { - getMembersAsync(new SimpleApiCallback>(callback) { - @Override - public void onSuccess(List info) { - List res = new ArrayList<>(); - - for (RoomMember m : info) { - if (RoomMember.MEMBERSHIP_JOIN.equals(m.membership) && !mMyUserId.equals(m.getUserId())) { - res.add(m); - } - } - - callback.onSuccess(res); - } - }); - } - - //================================================================================ - // Account data management - //================================================================================ - - /** - * Handle private user data events. - * - * @param accountDataEvents the account events. - */ - private void handleAccountDataEvents(List accountDataEvents) { - if ((null != accountDataEvents) && (accountDataEvents.size() > 0)) { - // manage the account events - for (Event accountDataEvent : accountDataEvents) { - String eventType = accountDataEvent.getType(); - - final RoomSummary summary = (null != getStore()) ? getStore().getSummary(getRoomId()) : null; - if (eventType.equals(Event.EVENT_TYPE_READ_MARKER)) { - if (summary != null) { - final Event event = JsonUtils.toEvent(accountDataEvent.getContent()); - if (null != event && !TextUtils.equals(event.eventId, summary.getReadMarkerEventId())) { - Log.d(LOG_TAG, "## handleAccountDataEvents() : update the read marker to " + event.eventId + " in room " + getRoomId()); - if (TextUtils.isEmpty(event.eventId)) { - Log.e(LOG_TAG, "## handleAccountDataEvents() : null event id " + accountDataEvent.getContent()); - } - summary.setReadMarkerEventId(event.eventId); - getStore().flushSummary(summary); - mDataHandler.onReadMarkerEvent(getRoomId()); - } - } - } else { - mAccountData.handleTagEvent(accountDataEvent); - if (Event.EVENT_TYPE_TAGS.equals(accountDataEvent.getType())) { - summary.setRoomTags(mAccountData.getKeys()); - getStore().flushSummary(summary); - mDataHandler.onRoomTagEvent(getRoomId()); - } else if (Event.EVENT_TYPE_URL_PREVIEW.equals(accountDataEvent.getType())) { - final JsonObject jsonObject = accountDataEvent.getContentAsJsonObject(); - if (jsonObject.has(AccountDataRestClient.ACCOUNT_DATA_KEY_URL_PREVIEW_DISABLE)) { - final boolean disabled = jsonObject.get(AccountDataRestClient.ACCOUNT_DATA_KEY_URL_PREVIEW_DISABLE).getAsBoolean(); - Set roomIdsWithoutURLPreview = mDataHandler.getStore().getRoomsWithoutURLPreviews(); - if (disabled) { - roomIdsWithoutURLPreview.add(getRoomId()); - } else { - roomIdsWithoutURLPreview.remove(getRoomId()); - } - - mDataHandler.getStore().setRoomsWithoutURLPreview(roomIdsWithoutURLPreview); - } - } - } - } - - if (null != getStore()) { - getStore().storeAccountData(getRoomId(), mAccountData); - } - } - } - - /** - * Add a tag to a room. - * Use this method to update the order of an existing tag. - * - * @param tag the new tag to add to the room. - * @param order the order. - * @param callback the operation callback - */ - private void addTag(String tag, Double order, final ApiCallback callback) { - // sanity check - if ((null != tag) && (null != order)) { - mDataHandler.getDataRetriever().getRoomsRestClient().addTag(getRoomId(), tag, order, callback); - } else { - if (null != callback) { - callback.onSuccess(null); - } - } - } - - /** - * Remove a tag to a room. - * - * @param tag the new tag to add to the room. - * @param callback the operation callback. - */ - private void removeTag(String tag, final ApiCallback callback) { - // sanity check - if (null != tag) { - mDataHandler.getDataRetriever().getRoomsRestClient().removeTag(getRoomId(), tag, callback); - } else { - if (null != callback) { - callback.onSuccess(null); - } - } - } - - /** - * Remove a tag and add another one. - * - * @param oldTag the tag to remove. - * @param newTag the new tag to add. Nil can be used. Then, no new tag will be added. - * @param newTagOrder the order of the new tag. - * @param callback the operation callback. - */ - public void replaceTag(final String oldTag, final String newTag, final Double newTagOrder, final ApiCallback callback) { - // remove tag - if ((null != oldTag) && (null == newTag)) { - removeTag(oldTag, callback); - } - // define a tag or define a new order - else if (((null == oldTag) && (null != newTag)) || TextUtils.equals(oldTag, newTag)) { - addTag(newTag, newTagOrder, callback); - } else { - removeTag(oldTag, new SimpleApiCallback(callback) { - @Override - public void onSuccess(Void info) { - addTag(newTag, newTagOrder, callback); - } - }); - } - } - - //============================================================================================================== - // URL preview - //============================================================================================================== - - /** - * Tells if the URL preview has been allowed by the user. - * - * @return @return true if allowed. - */ - public boolean isURLPreviewAllowedByUser() { - return !getDataHandler().getStore().getRoomsWithoutURLPreviews().contains(getRoomId()); - } - - /** - * Update the user enabled room url preview - * - * @param status the new status - * @param callback the asynchronous callback - */ - public void setIsURLPreviewAllowedByUser(boolean status, ApiCallback callback) { - mDataHandler.getDataRetriever().getRoomsRestClient().updateURLPreviewStatus(getRoomId(), status, callback); - } - - //============================================================================================================== - // Room events dispatcher - //============================================================================================================== - - /** - * Add an event listener to this room. Only events relative to the room will come down. - * - * @param eventListener the event listener to add - */ - public void addEventListener(final IMXEventListener eventListener) { - // sanity check - if (null == eventListener) { - Log.e(LOG_TAG, "addEventListener : eventListener is null"); - return; - } - - // GA crash : should never happen but got it. - if (null == mDataHandler) { - Log.e(LOG_TAG, "addEventListener : mDataHandler is null"); - return; - } - - // Create a global listener that we'll add to the data handler - IMXEventListener globalListener = new MXRoomEventListener(this, eventListener); - - mEventListeners.put(eventListener, globalListener); - - // GA crash - if (null != mDataHandler) { - mDataHandler.addListener(globalListener); - } - } - - /** - * Remove an event listener. - * - * @param eventListener the event listener to remove - */ - public void removeEventListener(IMXEventListener eventListener) { - // sanity check - if ((null != eventListener) && (null != mDataHandler)) { - mDataHandler.removeListener(mEventListeners.get(eventListener)); - mEventListeners.remove(eventListener); - } - } - - //============================================================================================================== - // Send methods - //============================================================================================================== - - /** - * Send an event content to the room. - * The event is updated with the data provided by the server - * The provided event contains the error description. - * - * @param event the message - * @param callback the callback with the created event - */ - public void sendEvent(final Event event, final ApiCallback callback) { - // wait that the room is synced before sending messages - if (!mIsReady || !isJoined()) { - mDataHandler.updateEventState(event, Event.SentState.WAITING_RETRY); - try { - callback.onNetworkError(null); - } catch (Exception e) { - Log.e(LOG_TAG, "sendEvent exception " + e.getMessage(), e); - } - return; - } - - final String prevEventId = event.eventId; - - final ApiCallback localCB = new ApiCallback() { - @Override - public void onSuccess(final CreatedEvent createdEvent) { - if (null != getStore()) { - // remove the tmp event - getStore().deleteEvent(event); - } - - // replace the tmp event id by the final one - boolean isReadMarkerUpdated = TextUtils.equals(getReadMarkerEventId(), event.eventId); - - // update the event with the server response - event.eventId = createdEvent.eventId; - event.originServerTs = System.currentTimeMillis(); - mDataHandler.updateEventState(event, Event.SentState.SENT); - - // the message echo is not yet echoed - if (null != getStore() && !getStore().doesEventExist(createdEvent.eventId, getRoomId())) { - getStore().storeLiveRoomEvent(event); - } - - // send the dedicated read receipt asap - markAllAsRead(isReadMarkerUpdated, null); - - if (null != getStore()) { - getStore().commit(); - } - mDataHandler.onEventSent(event, prevEventId); - - try { - callback.onSuccess(null); - } catch (Exception e) { - Log.e(LOG_TAG, "sendEvent exception " + e.getMessage(), e); - } - } - - @Override - public void onNetworkError(Exception e) { - event.unsentException = e; - mDataHandler.updateEventState(event, Event.SentState.UNDELIVERED); - try { - callback.onNetworkError(e); - } catch (Exception anException) { - Log.e(LOG_TAG, "sendEvent exception " + anException.getMessage(), anException); - } - } - - @Override - public void onMatrixError(MatrixError e) { - event.unsentMatrixError = e; - mDataHandler.updateEventState(event, Event.SentState.UNDELIVERED); - - if (MatrixError.isConfigurationErrorCode(e.errcode)) { - mDataHandler.onConfigurationError(e.errcode); - } else { - try { - callback.onMatrixError(e); - } catch (Exception anException) { - Log.e(LOG_TAG, "sendEvent exception " + anException.getMessage(), anException); - } - } - } - - @Override - public void onUnexpectedError(Exception e) { - event.unsentException = e; - mDataHandler.updateEventState(event, Event.SentState.UNDELIVERED); - try { - callback.onUnexpectedError(e); - } catch (Exception anException) { - Log.e(LOG_TAG, "sendEvent exception " + anException.getMessage(), anException); - } - } - }; - - if (isEncrypted() && (null != mDataHandler.getCrypto())) { - mDataHandler.updateEventState(event, Event.SentState.ENCRYPTING); - - // Store the "m.relates_to" data and remove them from event content before encrypting the event content - final JsonElement relatesTo; - - JsonObject contentAsJsonObject = event.getContentAsJsonObject(); - - if (contentAsJsonObject != null - && contentAsJsonObject.has("m.relates_to")) { - // Get a copy of "m.relates_to" data... - relatesTo = contentAsJsonObject.get("m.relates_to"); - - // ... and remove "m.relates_to" data from the content before encrypting it - contentAsJsonObject.remove("m.relates_to"); - } else { - relatesTo = null; - } - - // Encrypt the content before sending - mDataHandler.getCrypto() - .encryptEventContent(contentAsJsonObject, event.getType(), this, new ApiCallback() { - @Override - public void onSuccess(MXEncryptEventContentResult encryptEventContentResult) { - // update the event content with the encrypted data - event.type = encryptEventContentResult.mEventType; - - // Add the "m.relates_to" data to the encrypted event here - JsonObject encryptedContent = encryptEventContentResult.mEventContent.getAsJsonObject(); - if (relatesTo != null) { - encryptedContent.add("m.relates_to", relatesTo); - } - event.updateContent(encryptedContent); - mDataHandler.decryptEvent(event, null); - - // sending in progress - mDataHandler.updateEventState(event, Event.SentState.SENDING); - mDataHandler.getDataRetriever().getRoomsRestClient().sendEventToRoom(event.eventId, getRoomId(), - encryptEventContentResult.mEventType, encryptEventContentResult.mEventContent.getAsJsonObject(), localCB); - } - - @Override - public void onNetworkError(Exception e) { - event.unsentException = e; - mDataHandler.updateEventState(event, Event.SentState.UNDELIVERED); - - if (null != callback) { - callback.onNetworkError(e); - } - } - - @Override - public void onMatrixError(MatrixError e) { - // update the sent state if the message encryption failed because there are unknown devices. - if ((e instanceof MXCryptoError) && TextUtils.equals(((MXCryptoError) e).errcode, MXCryptoError.UNKNOWN_DEVICES_CODE)) { - event.mSentState = Event.SentState.FAILED_UNKNOWN_DEVICES; - } else { - event.mSentState = Event.SentState.UNDELIVERED; - } - event.unsentMatrixError = e; - mDataHandler.onEventSentStateUpdated(event); - - if (null != callback) { - callback.onMatrixError(e); - } - } - - @Override - public void onUnexpectedError(Exception e) { - event.unsentException = e; - mDataHandler.updateEventState(event, Event.SentState.UNDELIVERED); - - if (null != callback) { - callback.onUnexpectedError(e); - } - } - }); - } else { - mDataHandler.updateEventState(event, Event.SentState.SENDING); - - if (Event.EVENT_TYPE_MESSAGE.equals(event.getType())) { - mDataHandler.getDataRetriever().getRoomsRestClient() - .sendMessage(event.eventId, getRoomId(), JsonUtils.toMessage(event.getContent()), localCB); - } else { - mDataHandler.getDataRetriever().getRoomsRestClient() - .sendEventToRoom(event.eventId, getRoomId(), event.getType(), event.getContentAsJsonObject(), localCB); - } - } - } - - /** - * Cancel the event sending. - * Any media upload will be cancelled too. - * The event becomes undeliverable. - * - * @param event the message - */ - public void cancelEventSending(final Event event) { - if (null != event) { - if ((Event.SentState.UNSENT == event.mSentState) - || (Event.SentState.SENDING == event.mSentState) - || (Event.SentState.WAITING_RETRY == event.mSentState) - || (Event.SentState.ENCRYPTING == event.mSentState)) { - - // the message cannot be sent anymore - mDataHandler.updateEventState(event, Event.SentState.UNDELIVERED); - } - - List urls = event.getMediaUrls(); - MXMediasCache cache = mDataHandler.getMediasCache(); - - for (String url : urls) { - cache.cancelUpload(url); - cache.cancelDownload(cache.downloadIdFromUrl(url)); - } - } - } - - /** - * Redact an event from the room. - * - * @param eventId the event's id - * @param callback the callback with the redacted event - */ - public void redact(final String eventId, final ApiCallback callback) { - mDataHandler.getDataRetriever().getRoomsRestClient().redactEvent(getRoomId(), eventId, new SimpleApiCallback(callback) { - @Override - public void onSuccess(Event event) { - Event redactedEvent = (null != getStore()) ? getStore().getEvent(eventId, getRoomId()) : null; - - // test if the redacted event has been echoed - // it it was not echoed, the event must be pruned to remove useless data - // the room summary will be updated when the server will echo the redacted event - if ((null != redactedEvent) && ((null == redactedEvent.unsigned) || (null == redactedEvent.unsigned.redacted_because))) { - redactedEvent.prune(null); - getStore().storeLiveRoomEvent(redactedEvent); - getStore().commit(); - } - - if (null != callback) { - callback.onSuccess(redactedEvent); - } - } - }); - } - - /** - * Redact an event from the room. - * - * @param eventId the event's id - * @param score the score - * @param reason the redaction reason - * @param callback the callback with the created event - */ - public void report(String eventId, int score, String reason, ApiCallback callback) { - mDataHandler.getDataRetriever().getRoomsRestClient().reportEvent(getRoomId(), eventId, score, reason, callback); - } - - //================================================================================ - // Member actions - //================================================================================ - - /** - * Invite an user to this room. - * - * @param userId the user id - * @param callback the callback for when done - */ - public void invite(String userId, ApiCallback callback) { - if (null != userId) { - invite(Collections.singletonList(userId), callback); - } - } - - /** - * Invite an user to a room based on their email address to this room. - * - * @param email the email address - * @param callback the callback for when done - */ - public void inviteByEmail(String email, ApiCallback callback) { - if (null != email) { - invite(Collections.singletonList(email), callback); - } - } - - /** - * Invite users to this room. - * The identifiers are either ini Id or email address. - * - * @param identifiers the identifiers list - * @param callback the callback for when done - */ - public void invite(List identifiers, ApiCallback callback) { - if (null != identifiers) { - invite(identifiers.iterator(), callback); - } - } - - /** - * Invite some users to this room. - * - * @param identifiers the identifiers iterator - * @param callback the callback for when done - */ - private void invite(final Iterator identifiers, final ApiCallback callback) { - if (!identifiers.hasNext()) { - callback.onSuccess(null); - return; - } - - final ApiCallback localCallback = new SimpleApiCallback(callback) { - @Override - public void onSuccess(Void info) { - invite(identifiers, callback); - } - }; - - String identifier = identifiers.next(); - - if (android.util.Patterns.EMAIL_ADDRESS.matcher(identifier).matches()) { - mDataHandler.getDataRetriever().getRoomsRestClient().inviteByEmailToRoom(getRoomId(), identifier, localCallback); - } else { - mDataHandler.getDataRetriever().getRoomsRestClient().inviteUserToRoom(getRoomId(), identifier, localCallback); - } - } - - /** - * Leave the room. - * - * @param callback the callback for when done - */ - public void leave(final ApiCallback callback) { - mIsLeaving = true; - mDataHandler.onRoomInternalUpdate(getRoomId()); - - mDataHandler.getDataRetriever().getRoomsRestClient().leaveRoom(getRoomId(), new ApiCallback() { - @Override - public void onSuccess(Void info) { - if (mDataHandler.isAlive()) { - mIsLeaving = false; - - // delete references to the room - mDataHandler.deleteRoom(getRoomId()); - - if (null != getStore()) { - Log.d(LOG_TAG, "leave : commit"); - getStore().commit(); - } - - try { - callback.onSuccess(info); - } catch (Exception e) { - Log.e(LOG_TAG, "leave exception " + e.getMessage(), e); - } - - mDataHandler.onLeaveRoom(getRoomId()); - } - } - - @Override - public void onNetworkError(Exception e) { - mIsLeaving = false; - - try { - callback.onNetworkError(e); - } catch (Exception anException) { - Log.e(LOG_TAG, "leave exception " + anException.getMessage(), anException); - } - - mDataHandler.onRoomInternalUpdate(getRoomId()); - } - - @Override - public void onMatrixError(MatrixError e) { - // the room was not anymore defined server side - // race condition ? - if (e.mStatus == 404) { - onSuccess(null); - } else { - mIsLeaving = false; - - try { - callback.onMatrixError(e); - } catch (Exception anException) { - Log.e(LOG_TAG, "leave exception " + anException.getMessage(), anException); - } - - mDataHandler.onRoomInternalUpdate(getRoomId()); - } - } - - @Override - public void onUnexpectedError(Exception e) { - mIsLeaving = false; - - try { - callback.onUnexpectedError(e); - } catch (Exception anException) { - Log.e(LOG_TAG, "leave exception " + anException.getMessage(), anException); - } - - mDataHandler.onRoomInternalUpdate(getRoomId()); - } - }); - } - - /** - * Forget the room. - * - * @param callback the callback for when done - */ - public void forget(final ApiCallback callback) { - mDataHandler.getDataRetriever().getRoomsRestClient().forgetRoom(getRoomId(), new SimpleApiCallback(callback) { - @Override - public void onSuccess(Void info) { - if (mDataHandler.isAlive()) { - // don't call onSuccess.deleteRoom because it moves an existing room to historical store - IMXStore store = mDataHandler.getStore(getRoomId()); - - if (null != store) { - store.deleteRoom(getRoomId()); - store.commit(); - } - - try { - callback.onSuccess(info); - } catch (Exception e) { - Log.e(LOG_TAG, "forget exception " + e.getMessage(), e); - } - } - } - }); - } - - - /** - * Kick a user from the room. - * - * @param userId the user id - * @param callback the async callback - */ - public void kick(String userId, ApiCallback callback) { - mDataHandler.getDataRetriever().getRoomsRestClient().kickFromRoom(getRoomId(), userId, callback); - } - - /** - * Ban a user from the room. - * - * @param userId the user id - * @param reason ban reason - * @param callback the async callback - */ - public void ban(String userId, String reason, ApiCallback callback) { - BannedUser user = new BannedUser(); - user.userId = userId; - if (!TextUtils.isEmpty(reason)) { - user.reason = reason; - } - mDataHandler.getDataRetriever().getRoomsRestClient().banFromRoom(getRoomId(), user, callback); - } - - /** - * Unban a user. - * - * @param userId the user id - * @param callback the async callback - */ - public void unban(String userId, ApiCallback callback) { - BannedUser user = new BannedUser(); - user.userId = userId; - - mDataHandler.getDataRetriever().getRoomsRestClient().unbanFromRoom(getRoomId(), user, callback); - } - - //================================================================================ - // Encryption - //================================================================================ - - private ApiCallback mRoomEncryptionCallback; - - private final MXEventListener mEncryptionListener = new MXEventListener() { - @Override - public void onLiveEvent(Event event, RoomState roomState) { - if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE_ENCRYPTION)) { - if (null != mRoomEncryptionCallback) { - mRoomEncryptionCallback.onSuccess(null); - mRoomEncryptionCallback = null; - } - } - } - }; - - /** - * @return if the room content is encrypted - */ - public boolean isEncrypted() { - return getState().isEncrypted(); - } - - /** - * Enable the encryption. - * - * @param algorithm the used algorithm - * @param callback the asynchronous callback - */ - public void enableEncryptionWithAlgorithm(final String algorithm, final ApiCallback callback) { - // ensure that the crypto has been update - if (null != mDataHandler.getCrypto() && !TextUtils.isEmpty(algorithm)) { - Map params = new HashMap<>(); - params.put("algorithm", algorithm); - - if (null != callback) { - mRoomEncryptionCallback = callback; - addEventListener(mEncryptionListener); - } - - mDataHandler.getDataRetriever().getRoomsRestClient() - .sendStateEvent(getRoomId(), Event.EVENT_TYPE_MESSAGE_ENCRYPTION, null, params, new ApiCallback() { - @Override - public void onSuccess(Void info) { - // Wait for the event coming back from the hs - } - - @Override - public void onNetworkError(Exception e) { - if (null != callback) { - callback.onNetworkError(e); - removeEventListener(mEncryptionListener); - } - } - - @Override - public void onMatrixError(MatrixError e) { - if (null != callback) { - callback.onMatrixError(e); - removeEventListener(mEncryptionListener); - } - } - - @Override - public void onUnexpectedError(Exception e) { - if (null != callback) { - callback.onUnexpectedError(e); - removeEventListener(mEncryptionListener); - } - } - }); - } else if (null != callback) { - if (null == mDataHandler.getCrypto()) { - callback.onMatrixError(new MXCryptoError(MXCryptoError.ENCRYPTING_NOT_ENABLED_ERROR_CODE, - MXCryptoError.ENCRYPTING_NOT_ENABLED_REASON, MXCryptoError.ENCRYPTING_NOT_ENABLED_REASON)); - } else { - callback.onMatrixError(new MXCryptoError(MXCryptoError.MISSING_FIELDS_ERROR_CODE, - MXCryptoError.UNABLE_TO_ENCRYPT, MXCryptoError.MISSING_FIELDS_REASON)); - } - } - } - - //============================================================================================================== - // Room events helper - //============================================================================================================== - - private RoomMediaMessagesSender mRoomMediaMessagesSender; - - /** - * Init the mRoomMediaMessagesSender instance - */ - private void initRoomMediaMessagesSender() { - if (null == mRoomMediaMessagesSender) { - mRoomMediaMessagesSender = new RoomMediaMessagesSender(getStore().getContext(), mDataHandler, this); - } - } - - /** - * Send a text message asynchronously. - * - * @param text the unformatted text - * @param htmlFormattedText the HTML formatted text - * @param format the formatted text format - * @param listener the event creation listener - */ - public void sendTextMessage(String text, - String htmlFormattedText, - String format, - RoomMediaMessage.EventCreationListener listener) { - sendTextMessage(text, htmlFormattedText, format, null, Message.MSGTYPE_TEXT, listener); - } - - /** - * Send a text message asynchronously. - * - * @param text the unformatted text - * @param htmlFormattedText the HTML formatted text - * @param format the formatted text format - * @param replyToEvent the event to reply to, or null - * @param listener the event creation listener - */ - public void sendTextMessage(String text, - String htmlFormattedText, - String format, - @Nullable Event replyToEvent, - RoomMediaMessage.EventCreationListener listener) { - sendTextMessage(text, htmlFormattedText, format, replyToEvent, Message.MSGTYPE_TEXT, listener); - } - - /** - * Send an emote message asynchronously. - * - * @param text the unformatted text - * @param htmlFormattedText the HTML formatted text - * @param format the formatted text format - * @param listener the event creation listener - */ - public void sendEmoteMessage(String text, - String htmlFormattedText, - String format, - final RoomMediaMessage.EventCreationListener listener) { - sendTextMessage(text, htmlFormattedText, format, null, Message.MSGTYPE_EMOTE, listener); - } - - /** - * Send a text message asynchronously. - * - * @param text the unformatted text - * @param htmlFormattedText the HTML formatted text - * @param format the formatted text format - * @param replyToEvent the event to reply to (optional). Only event of type Event.EVENT_TYPE_MESSAGE are supported for the moment. - * @param msgType the message type - * @param listener the event creation listener - */ - private void sendTextMessage(String text, - String htmlFormattedText, - String format, - @Nullable Event replyToEvent, - String msgType, - final RoomMediaMessage.EventCreationListener listener) { - initRoomMediaMessagesSender(); - - RoomMediaMessage roomMediaMessage = new RoomMediaMessage(text, htmlFormattedText, format); - roomMediaMessage.setMessageType(msgType); - roomMediaMessage.setEventCreationListener(listener); - - if (canReplyTo(replyToEvent)) { - roomMediaMessage.setReplyToEvent(replyToEvent); - } - - mRoomMediaMessagesSender.send(roomMediaMessage); - } - - /** - * Indicate if replying to the provided event is supported. - * Only event of type Event.EVENT_TYPE_MESSAGE are supported for the moment, and for certain msgtype. - * - * @param replyToEvent the event to reply to - * @return true if it is possible to reply to this event - */ - public boolean canReplyTo(@Nullable Event replyToEvent) { - if (replyToEvent != null - && Event.EVENT_TYPE_MESSAGE.equals(replyToEvent.getType())) { - - // Cf. https://docs.google.com/document/d/1BPd4lBrooZrWe_3s_lHw_e-Dydvc7bXbm02_sV2k6Sc - String msgType = JsonUtils.getMessageMsgType(replyToEvent.getContentAsJsonObject()); - - if (msgType != null) { - switch (msgType) { - case Message.MSGTYPE_TEXT: - case Message.MSGTYPE_NOTICE: - case Message.MSGTYPE_EMOTE: - case Message.MSGTYPE_IMAGE: - case Message.MSGTYPE_VIDEO: - case Message.MSGTYPE_AUDIO: - case Message.MSGTYPE_FILE: - return true; - } - } - } - - return false; - } - - /** - * Send an media message asynchronously. - * - * @param roomMediaMessage the media message to send. - * @param maxThumbnailWidth the max thumbnail width - * @param maxThumbnailHeight the max thumbnail height - * @param listener the event creation listener - */ - public void sendMediaMessage(final RoomMediaMessage roomMediaMessage, - final int maxThumbnailWidth, - final int maxThumbnailHeight, - final RoomMediaMessage.EventCreationListener listener) { - initRoomMediaMessagesSender(); - - roomMediaMessage.setThumbnailSize(new Pair<>(maxThumbnailWidth, maxThumbnailHeight)); - roomMediaMessage.setEventCreationListener(listener); - - mRoomMediaMessagesSender.send(roomMediaMessage); - } - - /** - * Send a sticker message. - * - * @param event - * @param listener - */ - public void sendStickerMessage(Event event, final RoomMediaMessage.EventCreationListener listener) { - initRoomMediaMessagesSender(); - - RoomMediaMessage roomMediaMessage = new RoomMediaMessage(event); - roomMediaMessage.setMessageType(Event.EVENT_TYPE_STICKER); - roomMediaMessage.setEventCreationListener(listener); - - mRoomMediaMessagesSender.send(roomMediaMessage); - } - - //============================================================================================================== - // Unsent events management - //============================================================================================================== - - /** - * Provides the unsent messages list. - * - * @return the unsent events list - */ - public List getUnsentEvents() { - List unsent = new ArrayList<>(); - - if (null != getStore()) { - List undeliverableEvents = getStore().getUndeliveredEvents(getRoomId()); - List unknownDeviceEvents = getStore().getUnknownDeviceEvents(getRoomId()); - - if (null != undeliverableEvents) { - unsent.addAll(undeliverableEvents); - } - - if (null != unknownDeviceEvents) { - unsent.addAll(unknownDeviceEvents); - } - } - - return unsent; - } - - /** - * Delete an events list. - * - * @param events the events list - */ - public void deleteEvents(List events) { - if ((null != getStore()) && (null != events) && events.size() > 0) { - // reset the timestamp - for (Event event : events) { - getStore().deleteEvent(event); - } - - // update the summary - Event latestEvent = getStore().getLatestEvent(getRoomId()); - - // if there is an oldest event, use it to set a summary - if (latestEvent != null) { - if (RoomSummary.isSupportedEvent(latestEvent)) { - RoomSummary summary = getStore().getSummary(getRoomId()); - - if (null != summary) { - summary.setLatestReceivedEvent(latestEvent, getState()); - } else { - summary = new RoomSummary(null, latestEvent, getState(), mDataHandler.getUserId()); - } - - getStore().storeSummary(summary); - } - } - - getStore().commit(); - } - } - - /** - * Tell if room is Direct Chat - * - * @return true if is direct chat - */ - public boolean isDirect() { - return mDataHandler.getDirectChatRoomIdsList().contains(getRoomId()); - } - - @Nullable - public RoomSummary getRoomSummary() { - if (getDataHandler() == null) { - return null; - } - - if (getDataHandler().getStore() == null) { - return null; - } - - return getDataHandler().getStore().getSummary(getRoomId()); - } - - public int getNumberOfMembers() { - if (getDataHandler().isLazyLoadingEnabled()) { - return getNumberOfJoinedMembers() + getNumberOfInvitedMembers(); - } else { - return getState().getLoadedMembers().size(); - } - } - - public int getNumberOfJoinedMembers() { - if (getDataHandler().isLazyLoadingEnabled()) { - RoomSummary roomSummary = getRoomSummary(); - - if (roomSummary != null) { - return roomSummary.getNumberOfJoinedMembers(); - } else { - // Should not happen, fallback to loaded members - return getNumberOfLoadedJoinedMembers(); - } - } else { - return getNumberOfLoadedJoinedMembers(); - } - } - - private int getNumberOfLoadedJoinedMembers() { - int count = 0; - - for (RoomMember roomMember : getState().getLoadedMembers()) { - if (RoomMember.MEMBERSHIP_JOIN.equals(roomMember.membership)) { - count++; - } - } - - return count; - } - - public int getNumberOfInvitedMembers() { - if (getDataHandler().isLazyLoadingEnabled()) { - RoomSummary roomSummary = getRoomSummary(); - - if (roomSummary != null) { - return roomSummary.getNumberOfInvitedMembers(); - } else { - // Should not happen, fallback to loaded members - return getNumberOfLoadedInvitedMembers(); - } - } else { - return getNumberOfLoadedInvitedMembers(); - } - } - - private int getNumberOfLoadedInvitedMembers() { - int count = 0; - - for (RoomMember roomMember : getState().getLoadedMembers()) { - if (RoomMember.MEMBERSHIP_INVITE.equals(roomMember.membership)) { - count++; - } - } - - return count; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomAccountData.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomAccountData.java deleted file mode 100644 index 8a0d1e52..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomAccountData.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.data; - -import android.support.annotation.Nullable; - -import im.vector.matrix.android.internal.legacy.rest.model.Event; - -import java.util.Map; -import java.util.Set; - -/** - * Class representing private data that the user has defined for a room. - */ -public class RoomAccountData implements java.io.Serializable { - - private static final long serialVersionUID = -8406116277864521120L; - - // The tags the user defined for this room. - // The key is the tag name. The value, the associated MXRoomTag object. - private Map tags = null; - - /** - * Process an event that modifies room account data (like m.tag event). - * - * @param event an event - */ - public void handleTagEvent(Event event) { - if (event.getType().equals(Event.EVENT_TYPE_TAGS)) { - tags = RoomTag.roomTagsWithTagEvent(event); - } - } - - /** - * Provide a RoomTag for a key. - * - * @param key the key. - * @return the roomTag if it is found else null - */ - @Nullable - public RoomTag roomTag(String key) { - if ((null != tags) && tags.containsKey(key)) { - return tags.get(key); - } - - return null; - } - - /** - * @return true if some tags are defined - */ - public boolean hasTags() { - return (null != tags) && (tags.size() > 0); - } - - /** - * @return the list of keys, or null if no tag - */ - @Nullable - public Set getKeys() { - if (hasTags()) { - return tags.keySet(); - } else { - return null; - } - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomEmailInvitation.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomEmailInvitation.java deleted file mode 100644 index bfeb6c3b..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomEmailInvitation.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.data; - -import java.util.Map; - -/** - * Class representing the email invitation parameters - */ -public class RoomEmailInvitation { - - // the email invitation parameters - // earch parameter can be null - public String email; - public String signUrl; - public String roomName; - public String roomAvatarUrl; - public String inviterName; - public String guestAccessToken; - public String guestUserId; - - // the constructor - public RoomEmailInvitation(Map parameters) { - - if (null != parameters) { - email = parameters.get("email"); - signUrl = parameters.get("signurl"); - roomName = parameters.get("room_name"); - roomAvatarUrl = parameters.get("room_avatar_url"); - inviterName = parameters.get("inviter_name"); - guestAccessToken = parameters.get("guestAccessToken"); - guestUserId = parameters.get("guest_user_id"); - } - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomMediaMessage.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomMediaMessage.java deleted file mode 100755 index db07f4eb..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomMediaMessage.java +++ /dev/null @@ -1,901 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.data; - -import android.content.ClipData; -import android.content.ClipDescription; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.database.Cursor; -import android.graphics.Bitmap; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.os.Parcel; -import android.os.Parcelable; -import android.provider.MediaStore; -import android.provider.OpenableColumns; -import android.support.annotation.Nullable; -import android.text.TextUtils; -import android.util.Pair; -import android.webkit.MimeTypeMap; - -import im.vector.matrix.android.internal.legacy.listeners.IMXMediaUploadListener; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.message.Message; -import im.vector.matrix.android.internal.legacy.util.JsonUtils; -import im.vector.matrix.android.internal.legacy.util.Log; -import im.vector.matrix.android.internal.legacy.util.ResourceUtils; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; - -/** - * RoomMediaMessage encapsulates the media information to be sent. - */ -public class RoomMediaMessage implements Parcelable { - private static final String LOG_TAG = RoomMediaMessage.class.getSimpleName(); - - private static final Uri mDummyUri = Uri.parse("http://www.matrixdummy.org"); - - /** - * Interface to monitor event creation. - */ - public interface EventCreationListener { - /** - * The dedicated event has been created and added to the events list. - * - * @param roomMediaMessage the room media message. - */ - void onEventCreated(RoomMediaMessage roomMediaMessage); - - /** - * The event creation failed. - * - * @param roomMediaMessage the room media message. - * @param errorMessage the failure reason - */ - void onEventCreationFailed(RoomMediaMessage roomMediaMessage, String errorMessage); - - /** - * The media encryption failed. - * - * @param roomMediaMessage the room media message. - */ - void onEncryptionFailed(RoomMediaMessage roomMediaMessage); - } - - // the item is defined either from an uri - private Uri mUri; - private String mMimeType; - - // the message to send - private Event mEvent; - - // or a clipData Item - private ClipData.Item mClipDataItem; - - // the filename - private String mFileName; - - // Message.MSGTYPE_XX value - private String mMessageType; - - // The replyTo event - @Nullable - private Event mReplyToEvent; - - // thumbnail size - private Pair mThumbnailSize = new Pair<>(100, 100); - - // upload media upload listener - private transient IMXMediaUploadListener mMediaUploadListener; - - // event sending callback - private transient ApiCallback mEventSendingCallback; - - // event creation listener - private transient EventCreationListener mEventCreationListener; - - /** - * Constructor from a ClipData.Item. - * It might be used by a third party medias selection. - * - * @param clipDataItem the data item - * @param mimeType the mime type - */ - public RoomMediaMessage(ClipData.Item clipDataItem, String mimeType) { - mClipDataItem = clipDataItem; - mMimeType = mimeType; - } - - /** - * Constructor for a text message. - * - * @param text the text - * @param htmlText the HTML text - * @param format the formatted text format - */ - public RoomMediaMessage(CharSequence text, String htmlText, String format) { - mClipDataItem = new ClipData.Item(text, htmlText); - mMimeType = (null == htmlText) ? ClipDescription.MIMETYPE_TEXT_PLAIN : format; - } - - /** - * Constructor from a media Uri/ - * - * @param uri the media uri - */ - public RoomMediaMessage(Uri uri) { - this(uri, null); - } - - /** - * Constructor from a media Uri/ - * - * @param uri the media uri - * @param filename the media file name - */ - public RoomMediaMessage(Uri uri, String filename) { - mUri = uri; - mFileName = filename; - } - - /** - * Constructor from an event. - * - * @param event the event - */ - public RoomMediaMessage(Event event) { - setEvent(event); - - Message message = JsonUtils.toMessage(event.getContent()); - if (null != message) { - setMessageType(message.msgtype); - } - } - - /** - * Constructor from a parcel - * - * @param source the parcel - */ - private RoomMediaMessage(Parcel source) { - mUri = unformatNullUri((Uri) source.readParcelable(Uri.class.getClassLoader())); - mMimeType = unformatNullString(source.readString()); - - CharSequence clipDataItemText = unformatNullString(source.readString()); - String clipDataItemHtml = unformatNullString(source.readString()); - Uri clipDataItemUri = unformatNullUri((Uri) source.readParcelable(Uri.class.getClassLoader())); - - if (!TextUtils.isEmpty(clipDataItemText) || !TextUtils.isEmpty(clipDataItemHtml) || (null != clipDataItemUri)) { - mClipDataItem = new ClipData.Item(clipDataItemText, clipDataItemHtml, null, clipDataItemUri); - } - - mFileName = unformatNullString(source.readString()); - } - - @Override - public java.lang.String toString() { - String description = ""; - - description += "mUri " + mUri; - description += " -- mMimeType " + mMimeType; - description += " -- mEvent " + mEvent; - description += " -- mClipDataItem " + mClipDataItem; - description += " -- mFileName " + mFileName; - description += " -- mMessageType " + mMessageType; - description += " -- mThumbnailSize " + mThumbnailSize; - - return description; - } - - //============================================================================================================== - // Parcelable - //============================================================================================================== - - /** - * Unformat parcelled String - * - * @param string the string to unformat - * @return the unformatted string - */ - private static String unformatNullString(final String string) { - if (TextUtils.isEmpty(string)) { - return null; - } - - return string; - } - - /** - * Convert null uri to a dummy one - * - * @param uri the uri to unformat - * @return the unformatted - */ - private static Uri unformatNullUri(final Uri uri) { - if ((null == uri) || mDummyUri.equals(uri)) { - return null; - } - - return uri; - } - - - @Override - public int describeContents() { - return 0; - } - - /** - * Convert null string to "" - * - * @param string the string to format - * @return the formatted string - */ - private static String formatNullString(final String string) { - if (TextUtils.isEmpty(string)) { - return ""; - } - - return string; - } - - private static String formatNullString(final CharSequence charSequence) { - if (TextUtils.isEmpty(charSequence)) { - return ""; - } - - return charSequence.toString(); - } - - /** - * Convert null uri to a dummy one - * - * @param uri the uri to format - * @return the formatted - */ - private static Uri formatNullUri(final Uri uri) { - if (null == uri) { - return mDummyUri; - } - - return uri; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeParcelable(formatNullUri(mUri), 0); - dest.writeString(formatNullString(mMimeType)); - - if (null == mClipDataItem) { - dest.writeString(""); - dest.writeString(""); - dest.writeParcelable(formatNullUri(null), 0); - } else { - dest.writeString(formatNullString(mClipDataItem.getText())); - dest.writeString(formatNullString(mClipDataItem.getHtmlText())); - dest.writeParcelable(formatNullUri(mClipDataItem.getUri()), 0); - } - - dest.writeString(formatNullString(mFileName)); - } - - // Creator - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public RoomMediaMessage createFromParcel(Parcel in) { - return new RoomMediaMessage(in); - } - - public RoomMediaMessage[] newArray(int size) { - return new RoomMediaMessage[size]; - } - }; - - //============================================================================================================== - // Setters / getters - //============================================================================================================== - - /** - * Set the message type. - * - * @param messageType the message type. - */ - public void setMessageType(String messageType) { - mMessageType = messageType; - } - - /** - * @return the message type. - */ - public String getMessageType() { - return mMessageType; - } - - /** - * Set the replyTo event. - * - * @param replyToEvent the event to reply to - */ - public void setReplyToEvent(@Nullable Event replyToEvent) { - mReplyToEvent = replyToEvent; - } - - /** - * @return the replyTo event. - */ - @Nullable - public Event getReplyToEvent() { - return mReplyToEvent; - } - - /** - * Update the inner event. - * - * @param event the new event. - */ - public void setEvent(Event event) { - mEvent = event; - } - - /** - * @return the inner event objects - */ - public Event getEvent() { - return mEvent; - } - - /** - * Update the thumbnail size. - * - * @param size the new thumbnail size. - */ - public void setThumbnailSize(Pair size) { - mThumbnailSize = size; - } - - /** - * @return the thumbnail size. - */ - public Pair getThumbnailSize() { - return mThumbnailSize; - } - - /** - * Update the media upload listener. - * - * @param mediaUploadListener the media upload listener. - */ - public void setMediaUploadListener(IMXMediaUploadListener mediaUploadListener) { - mMediaUploadListener = mediaUploadListener; - } - - /** - * @return the media upload listener. - */ - public IMXMediaUploadListener getMediaUploadListener() { - return mMediaUploadListener; - } - - /** - * Update the event sending callback. - * - * @param callback the callback - */ - public void setEventSendingCallback(ApiCallback callback) { - mEventSendingCallback = callback; - } - - /** - * @return the event sending callback. - */ - public ApiCallback getSendingCallback() { - return mEventSendingCallback; - } - - /** - * Update the listener - * - * @param eventCreationListener the new listener - */ - public void setEventCreationListener(EventCreationListener eventCreationListener) { - mEventCreationListener = eventCreationListener; - } - - /** - * @return the listener. - */ - public EventCreationListener getEventCreationListener() { - return mEventCreationListener; - } - - /** - * Retrieve the raw text contained in this Item. - * - * @return the raw text - */ - public CharSequence getText() { - if (null != mClipDataItem) { - return mClipDataItem.getText(); - } - return null; - } - - /** - * Retrieve the raw HTML text contained in this Item. - * - * @return the raw HTML text - */ - public String getHtmlText() { - if (null != mClipDataItem) { - return mClipDataItem.getHtmlText(); - } - - return null; - } - - /** - * Retrieve the Intent contained in this Item. - * - * @return the intent - */ - public Intent getIntent() { - if (null != mClipDataItem) { - return mClipDataItem.getIntent(); - } - - return null; - } - - /** - * Retrieve the URI contained in this Item. - * - * @return the Uri - */ - public Uri getUri() { - if (null != mUri) { - return mUri; - } else if (null != mClipDataItem) { - return mClipDataItem.getUri(); - } - - return null; - } - - /** - * Returns the mimetype. - * - * @param context the context - * @return the mimetype - */ - public String getMimeType(Context context) { - if ((null == mMimeType) && (null != getUri())) { - try { - Uri uri = getUri(); - mMimeType = context.getContentResolver().getType(uri); - - // try to find the mimetype from the filename - if (null == mMimeType) { - String extension = MimeTypeMap.getFileExtensionFromUrl(uri.toString().toLowerCase()); - if (extension != null) { - mMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); - } - } - - if (null != mMimeType) { - // the mimetype is sometimes in uppercase. - mMimeType = mMimeType.toLowerCase(); - } - } catch (Exception e) { - Log.e(LOG_TAG, "Failed to open resource input stream", e); - } - } - - return mMimeType; - } - - /** - * Gets the MINI_KIND image thumbnail. - * - * @param context the context - * @return the MINI_KIND thumbnail it it exists - */ - public Bitmap getMiniKindImageThumbnail(Context context) { - return getImageThumbnail(context, MediaStore.Images.Thumbnails.MINI_KIND); - } - - /** - * Gets the FULL_SCREEN image thumbnail. - * - * @param context the context - * @return the FULL_SCREEN thumbnail it it exists - */ - public Bitmap getFullScreenImageKindThumbnail(Context context) { - return getImageThumbnail(context, MediaStore.Images.Thumbnails.FULL_SCREEN_KIND); - } - - /** - * Gets the image thumbnail. - * - * @param context the context. - * @param kind the thumbnail kind. - * @return the thumbnail. - */ - private Bitmap getImageThumbnail(Context context, int kind) { - // sanity check - if ((null == getMimeType(context)) || !getMimeType(context).startsWith("image/")) { - return null; - } - - Bitmap thumbnailBitmap = null; - - try { - ContentResolver resolver = context.getContentResolver(); - - List uriPath = getUri().getPathSegments(); - Long imageId; - String lastSegment = (String) uriPath.get(uriPath.size() - 1); - - // > Kitkat - if (lastSegment.startsWith("image:")) { - lastSegment = lastSegment.substring("image:".length()); - } - - try { - imageId = Long.parseLong(lastSegment); - } catch (Exception e) { - imageId = null; - } - - if (null != imageId) { - thumbnailBitmap = MediaStore.Images.Thumbnails.getThumbnail(resolver, imageId, kind, null); - } - } catch (Exception e) { - Log.e(LOG_TAG, "MediaStore.Images.Thumbnails.getThumbnail " + e.getMessage(), e); - } - - return thumbnailBitmap; - } - - /** - * @param context the context - * @return the filename - */ - public String getFileName(Context context) { - if ((null == mFileName) && (null != getUri())) { - Uri mediaUri = getUri(); - - if (null != mediaUri) { - try { - if (mediaUri.toString().startsWith("content://")) { - Cursor cursor = null; - try { - cursor = context.getContentResolver().query(mediaUri, null, null, null, null); - if (cursor != null && cursor.moveToFirst()) { - mFileName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); - } - } catch (Exception e) { - Log.e(LOG_TAG, "cursor.getString " + e.getMessage(), e); - } finally { - if (null != cursor) { - cursor.close(); - } - } - - if (TextUtils.isEmpty(mFileName)) { - List uriPath = mediaUri.getPathSegments(); - mFileName = (String) uriPath.get(uriPath.size() - 1); - } - } else if (mediaUri.toString().startsWith("file://")) { - mFileName = mediaUri.getLastPathSegment(); - } - } catch (Exception e) { - mFileName = null; - } - } - } - - return mFileName; - } - - /** - * Save a media into a dedicated folder - * - * @param context the context - * @param folder the folder. - */ - public void saveMedia(Context context, File folder) { - mFileName = null; - Uri mediaUri = getUri(); - - if (null != mediaUri) { - try { - ResourceUtils.Resource resource = ResourceUtils.openResource(context, mediaUri, getMimeType(context)); - - if (null == resource) { - Log.e(LOG_TAG, "## saveMedia : Fail to retrieve the resource " + mediaUri); - } else { - mUri = saveFile(folder, resource.mContentStream, getFileName(context), resource.mMimeType); - resource.mContentStream.close(); - } - } catch (Exception e) { - Log.e(LOG_TAG, "## saveMedia : failed " + e.getMessage(), e); - } - } - } - - /** - * Save a file in a dedicated directory. - * The filename is optional. - * - * @param folder the destination folder - * @param stream the file stream - * @param defaultFileName the filename, null to generate a new one - * @param mimeType the file mimetype. - * @return the file uri - */ - private static Uri saveFile(File folder, InputStream stream, String defaultFileName, String mimeType) { - String filename = defaultFileName; - - if (null == filename) { - filename = "file" + System.currentTimeMillis(); - - if (null != mimeType) { - String extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType); - - if (null != extension) { - filename += "." + extension; - } - } - } - - Uri fileUri = null; - - try { - File file = new File(folder, filename); - - // if the file exits, delete it - if (file.exists()) { - file.delete(); - } - - FileOutputStream fos = new FileOutputStream(file.getPath()); - - try { - byte[] buf = new byte[1024 * 32]; - - int len; - while ((len = stream.read(buf)) != -1) { - fos.write(buf, 0, len); - } - } catch (Exception e) { - Log.e(LOG_TAG, "## saveFile failed " + e.getMessage(), e); - } - - fos.flush(); - fos.close(); - stream.close(); - - fileUri = Uri.fromFile(file); - } catch (Exception e) { - Log.e(LOG_TAG, "## saveFile failed " + e.getMessage(), e); - } - - return fileUri; - } - - //============================================================================================================== - // Dispatchers - //============================================================================================================== - - /** - * Dispatch onEventCreated. - */ - void onEventCreated() { - if (null != getEventCreationListener()) { - try { - getEventCreationListener().onEventCreated(this); - } catch (Exception e) { - Log.e(LOG_TAG, "## onEventCreated() failed : " + e.getMessage(), e); - } - } - - // clear the listener - mEventCreationListener = null; - } - - /** - * Dispatch onEventCreationFailed. - */ - void onEventCreationFailed(String errorMessage) { - if (null != getEventCreationListener()) { - try { - getEventCreationListener().onEventCreationFailed(this, errorMessage); - } catch (Exception e) { - Log.e(LOG_TAG, "## onEventCreationFailed() failed : " + e.getMessage(), e); - } - } - - // clear the listeners - mMediaUploadListener = null; - mEventSendingCallback = null; - mEventCreationListener = null; - } - - /** - * Dispatch onEncryptionFailed. - */ - void onEncryptionFailed() { - if (null != getEventCreationListener()) { - try { - getEventCreationListener().onEncryptionFailed(this); - } catch (Exception e) { - Log.e(LOG_TAG, "## onEncryptionFailed() failed : " + e.getMessage(), e); - } - } - - // clear the listeners - mMediaUploadListener = null; - mEventSendingCallback = null; - mEventCreationListener = null; - } - - //============================================================================================================== - // Retrieve RoomMediaMessages from intents. - //============================================================================================================== - - /** - * List the item provided in an intent. - * - * @param intent the intent. - * @return the RoomMediaMessages list - */ - public static List listRoomMediaMessages(Intent intent) { - return listRoomMediaMessages(intent, null); - } - - /** - * List the item provided in an intent. - * - * @param intent the intent. - * @param loader the class loader. - * @return the room list - */ - public static List listRoomMediaMessages(Intent intent, ClassLoader loader) { - List roomMediaMessages = new ArrayList<>(); - - - if (null != intent) { - // chrome adds many items when sharing an web page link - // so, test first the type - if (TextUtils.equals(intent.getType(), ClipDescription.MIMETYPE_TEXT_PLAIN)) { - String message = intent.getStringExtra(Intent.EXTRA_TEXT); - - if (null == message) { - CharSequence sequence = intent.getCharSequenceExtra(Intent.EXTRA_TEXT); - if (null != sequence) { - message = sequence.toString(); - } - } - - String subject = intent.getStringExtra(Intent.EXTRA_SUBJECT); - - if (!TextUtils.isEmpty(subject)) { - if (TextUtils.isEmpty(message)) { - message = subject; - } else if (android.util.Patterns.WEB_URL.matcher(message).matches()) { - message = subject + "\n" + message; - } - } - - if (!TextUtils.isEmpty(message)) { - roomMediaMessages.add(new RoomMediaMessage(message, null, intent.getType())); - return roomMediaMessages; - } - } - - ClipData clipData = null; - List mimetypes = null; - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - clipData = intent.getClipData(); - } - - // multiple data - if (null != clipData) { - if (null != clipData.getDescription()) { - if (0 != clipData.getDescription().getMimeTypeCount()) { - mimetypes = new ArrayList<>(); - - for (int i = 0; i < clipData.getDescription().getMimeTypeCount(); i++) { - mimetypes.add(clipData.getDescription().getMimeType(i)); - } - - // if the filter is "accept anything" the mimetype does not make sense - if (1 == mimetypes.size()) { - if (mimetypes.get(0).endsWith("/*")) { - mimetypes = null; - } - } - } - } - - int count = clipData.getItemCount(); - - for (int i = 0; i < count; i++) { - ClipData.Item item = clipData.getItemAt(i); - String mimetype = null; - - if (null != mimetypes) { - if (i < mimetypes.size()) { - mimetype = mimetypes.get(i); - } else { - mimetype = mimetypes.get(0); - } - - // uris list is not a valid mimetype - if (TextUtils.equals(mimetype, ClipDescription.MIMETYPE_TEXT_URILIST)) { - mimetype = null; - } - } - - roomMediaMessages.add(new RoomMediaMessage(item, mimetype)); - } - } else if (null != intent.getData()) { - roomMediaMessages.add(new RoomMediaMessage(intent.getData())); - } else { - Bundle bundle = intent.getExtras(); - - if (null != bundle) { - // provide a custom loader - bundle.setClassLoader(RoomMediaMessage.class.getClassLoader()); - // list the Uris list - if (bundle.containsKey(Intent.EXTRA_STREAM)) { - try { - Object streamUri = bundle.get(Intent.EXTRA_STREAM); - - if (streamUri instanceof Uri) { - roomMediaMessages.add(new RoomMediaMessage((Uri) streamUri)); - } else if (streamUri instanceof List) { - List streams = (List) streamUri; - - for (Object object : streams) { - if (object instanceof Uri) { - roomMediaMessages.add(new RoomMediaMessage((Uri) object)); - } else if (object instanceof RoomMediaMessage) { - roomMediaMessages.add((RoomMediaMessage) object); - } - } - } - } catch (Exception e) { - Log.e(LOG_TAG, "fail to extract the extra stream", e); - } - } - } - } - } - - return roomMediaMessages; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomMediaMessagesSender.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomMediaMessagesSender.java deleted file mode 100755 index 0e114c5f..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomMediaMessagesSender.java +++ /dev/null @@ -1,983 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.data; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.media.ThumbnailUtils; -import android.net.Uri; -import android.os.HandlerThread; -import android.os.Looper; -import android.provider.MediaStore; -import android.text.Html; -import android.text.TextUtils; -import android.util.Pair; - -import im.vector.matrix.android.R; -import im.vector.matrix.android.internal.legacy.MXDataHandler; -import im.vector.matrix.android.internal.legacy.crypto.MXEncryptedAttachments; -import im.vector.matrix.android.internal.legacy.db.MXMediasCache; -import im.vector.matrix.android.internal.legacy.listeners.MXMediaUploadListener; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.rest.model.message.AudioMessage; -import im.vector.matrix.android.internal.legacy.rest.model.message.FileMessage; -import im.vector.matrix.android.internal.legacy.rest.model.message.ImageMessage; -import im.vector.matrix.android.internal.legacy.rest.model.message.MediaMessage; -import im.vector.matrix.android.internal.legacy.rest.model.message.Message; -import im.vector.matrix.android.internal.legacy.rest.model.message.RelatesTo; -import im.vector.matrix.android.internal.legacy.rest.model.message.VideoMessage; -import im.vector.matrix.android.internal.legacy.util.ImageUtils; -import im.vector.matrix.android.internal.legacy.util.JsonUtils; -import im.vector.matrix.android.internal.legacy.util.Log; -import im.vector.matrix.android.internal.legacy.util.PermalinkUtils; -import im.vector.matrix.android.internal.legacy.util.ResourceUtils; - -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -/** - * Room helper to send media messages in the right order. - */ -class RoomMediaMessagesSender { - private static final String LOG_TAG = RoomMediaMessagesSender.class.getSimpleName(); - - // pending events list - private final List mPendingRoomMediaMessages = new ArrayList<>(); - - // linked room - private final Room mRoom; - - // data handler - private final MXDataHandler mDataHandler; - - // linked context - private final Context mContext; - - // the sending item - private RoomMediaMessage mSendingRoomMediaMessage; - - // UI thread - private static android.os.Handler mUiHandler = null; - - // events creation threads - private static android.os.Handler mEventHandler = null; - - // encoding creation threads - private static android.os.Handler mEncodingHandler = null; - - /** - * Constructor - * - * @param context the context - * @param dataHandler the dataHanlder - * @param room the room - */ - RoomMediaMessagesSender(Context context, MXDataHandler dataHandler, Room room) { - mRoom = room; - mContext = context.getApplicationContext(); - mDataHandler = dataHandler; - - if (null == mUiHandler) { - mUiHandler = new android.os.Handler(Looper.getMainLooper()); - - HandlerThread eventHandlerThread = new HandlerThread("RoomDataItemsSender_event", Thread.MIN_PRIORITY); - eventHandlerThread.start(); - mEventHandler = new android.os.Handler(eventHandlerThread.getLooper()); - - HandlerThread encodingHandlerThread = new HandlerThread("RoomDataItemsSender_encoding", Thread.MIN_PRIORITY); - encodingHandlerThread.start(); - mEncodingHandler = new android.os.Handler(encodingHandlerThread.getLooper()); - } - } - - /** - * Send a new media message to the room - * - * @param roomMediaMessage the message to send - */ - void send(final RoomMediaMessage roomMediaMessage) { - mEventHandler.post(new Runnable() { - @Override - public void run() { - if (null == roomMediaMessage.getEvent()) { - Message message; - String mimeType = roomMediaMessage.getMimeType(mContext); - - // avoid null case - if (null == mimeType) { - mimeType = ""; - } - - if (null == roomMediaMessage.getUri()) { - message = buildTextMessage(roomMediaMessage); - } else if (mimeType.startsWith("image/")) { - message = buildImageMessage(roomMediaMessage); - } else if (mimeType.startsWith("video/")) { - message = buildVideoMessage(roomMediaMessage); - } else { - message = buildFileMessage(roomMediaMessage); - } - - if (null == message) { - Log.e(LOG_TAG, "## send " + roomMediaMessage + " not supported"); - - - mUiHandler.post(new Runnable() { - @Override - public void run() { - roomMediaMessage.onEventCreationFailed("not supported " + roomMediaMessage); - } - }); - return; - } - - roomMediaMessage.setMessageType(message.msgtype); - - if (roomMediaMessage.getReplyToEvent() != null) { - // Note: it is placed here, but may be moved to the outer event during the encryption of the content - message.relatesTo = new RelatesTo(); - message.relatesTo.dict = new HashMap<>(); - message.relatesTo.dict.put("event_id", roomMediaMessage.getReplyToEvent().eventId); - } - - Event event = new Event(message, mDataHandler.getUserId(), mRoom.getRoomId()); - - roomMediaMessage.setEvent(event); - } - - mDataHandler.updateEventState(roomMediaMessage.getEvent(), Event.SentState.UNSENT); - mRoom.storeOutgoingEvent(roomMediaMessage.getEvent()); - mDataHandler.getStore().commit(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - roomMediaMessage.onEventCreated(); - } - }); - - synchronized (LOG_TAG) { - if (!mPendingRoomMediaMessages.contains(roomMediaMessage)) { - mPendingRoomMediaMessages.add(roomMediaMessage); - } - } - - mUiHandler.post(new Runnable() { - @Override - public void run() { - // send the item - sendNext(); - } - }); - } - }); - } - - /** - * Skip the sending media item. - */ - private void skip() { - synchronized (LOG_TAG) { - mSendingRoomMediaMessage = null; - } - - sendNext(); - } - - /** - * Send the next pending item - */ - private void sendNext() { - RoomMediaMessage roomMediaMessage; - - synchronized (LOG_TAG) { - // please wait - if (null != mSendingRoomMediaMessage) { - return; - } - - if (!mPendingRoomMediaMessages.isEmpty()) { - mSendingRoomMediaMessage = mPendingRoomMediaMessages.get(0); - mPendingRoomMediaMessages.remove(0); - } else { - // nothing to do - return; - } - - roomMediaMessage = mSendingRoomMediaMessage; - } - - // upload the medias first - if (uploadMedias(roomMediaMessage)) { - return; - } - - // send the event - sendEvent(roomMediaMessage.getEvent()); - } - - /** - * Send the event after uploading the medias - * - * @param event the event to send - */ - private void sendEvent(final Event event) { - mUiHandler.post(new Runnable() { - @Override - public void run() { - // nothing more to upload - mRoom.sendEvent(event, new ApiCallback() { - private ApiCallback getCallback() { - ApiCallback callback; - - synchronized (LOG_TAG) { - callback = mSendingRoomMediaMessage.getSendingCallback(); - mSendingRoomMediaMessage.setEventSendingCallback(null); - mSendingRoomMediaMessage = null; - } - - return callback; - } - - @Override - public void onSuccess(Void info) { - ApiCallback callback = getCallback(); - - if (null != callback) { - try { - callback.onSuccess(null); - } catch (Exception e) { - Log.e(LOG_TAG, "## sendNext() failed " + e.getMessage(), e); - } - } - - sendNext(); - } - - @Override - public void onNetworkError(Exception e) { - ApiCallback callback = getCallback(); - - if (null != callback) { - try { - callback.onNetworkError(e); - } catch (Exception e2) { - Log.e(LOG_TAG, "## sendNext() failed " + e2.getMessage(), e2); - } - } - - sendNext(); - } - - @Override - public void onMatrixError(MatrixError e) { - ApiCallback callback = getCallback(); - - if (null != callback) { - try { - callback.onMatrixError(e); - } catch (Exception e2) { - Log.e(LOG_TAG, "## sendNext() failed " + e2.getMessage(), e2); - } - } - - sendNext(); - } - - @Override - public void onUnexpectedError(Exception e) { - ApiCallback callback = getCallback(); - - if (null != callback) { - try { - callback.onUnexpectedError(e); - } catch (Exception e2) { - Log.e(LOG_TAG, "## sendNext() failed " + e2.getMessage(), e2); - } - } - - sendNext(); - } - }); - } - }); - } - - //============================================================================================================== - // Messages builder methods. - //============================================================================================================== - - /** - * Build a text message from a RoomMediaMessage. - * - * @param roomMediaMessage the RoomMediaMessage. - * @return the message - */ - private Message buildTextMessage(RoomMediaMessage roomMediaMessage) { - CharSequence sequence = roomMediaMessage.getText(); - String htmlText = roomMediaMessage.getHtmlText(); - String text = null; - - if (null == sequence) { - if (null != htmlText) { - text = Html.fromHtml(htmlText).toString(); - } - } else { - text = sequence.toString(); - } - - // a text message cannot be null - if (TextUtils.isEmpty(text) && !TextUtils.equals(roomMediaMessage.getMessageType(), Message.MSGTYPE_EMOTE)) { - return null; - } - - Message message = new Message(); - message.msgtype = (null == roomMediaMessage.getMessageType()) ? Message.MSGTYPE_TEXT : roomMediaMessage.getMessageType(); - message.body = text; - - // an emote can have an empty body - if (null == message.body) { - message.body = ""; - } - - if (!TextUtils.isEmpty(htmlText)) { - message.formatted_body = htmlText; - message.format = Message.FORMAT_MATRIX_HTML; - } - - // Deals with in reply to event - Event replyToEvent = roomMediaMessage.getReplyToEvent(); - if (replyToEvent != null) { - // Cf. https://docs.google.com/document/d/1BPd4lBrooZrWe_3s_lHw_e-Dydvc7bXbm02_sV2k6Sc - String msgType = JsonUtils.getMessageMsgType(replyToEvent.getContentAsJsonObject()); - - // Build body and formatted body, depending of the `msgtype` of the event the user is replying to - if (msgType != null) { - // Compute the content of the event user is replying to - String replyToBody; - String replyToFormattedBody; - boolean replyToEventIsAlreadyAReply = false; - - switch (msgType) { - case Message.MSGTYPE_TEXT: - case Message.MSGTYPE_NOTICE: - case Message.MSGTYPE_EMOTE: - Message messageToReplyTo = JsonUtils.toMessage(replyToEvent.getContentAsJsonObject()); - - replyToBody = messageToReplyTo.body; - - if (TextUtils.isEmpty(messageToReplyTo.formatted_body)) { - replyToFormattedBody = messageToReplyTo.body; - } else { - replyToFormattedBody = messageToReplyTo.formatted_body; - } - - replyToEventIsAlreadyAReply = messageToReplyTo.relatesTo != null - && messageToReplyTo.relatesTo.dict != null - && !TextUtils.isEmpty(messageToReplyTo.relatesTo.dict.get("event_id")); - - break; - case Message.MSGTYPE_IMAGE: - replyToBody = mContext.getString(R.string.reply_to_an_image); - replyToFormattedBody = replyToBody; - break; - case Message.MSGTYPE_VIDEO: - replyToBody = mContext.getString(R.string.reply_to_a_video); - replyToFormattedBody = replyToBody; - break; - case Message.MSGTYPE_AUDIO: - replyToBody = mContext.getString(R.string.reply_to_an_audio_file); - replyToFormattedBody = replyToBody; - break; - case Message.MSGTYPE_FILE: - replyToBody = mContext.getString(R.string.reply_to_a_file); - replyToFormattedBody = replyToBody; - break; - default: - // Other msg types are not supported yet - Log.w(LOG_TAG, "Reply to: unsupported msgtype: " + msgType); - replyToBody = null; - replyToFormattedBody = null; - break; - } - - if (replyToBody != null) { - String replyContent; - if (TextUtils.isEmpty(message.formatted_body)) { - replyContent = message.body; - } else { - replyContent = message.formatted_body; - } - - message.body = includeReplyToToBody(replyToEvent, - replyToBody, - replyToEventIsAlreadyAReply, - message.body, - msgType.equals(Message.MSGTYPE_EMOTE)); - message.formatted_body = includeReplyToToFormattedBody(replyToEvent, - replyToFormattedBody, - replyToEventIsAlreadyAReply, - replyContent, - msgType.equals(Message.MSGTYPE_EMOTE)); - - // Note: we need to force the format to Message.FORMAT_MATRIX_HTML - message.format = Message.FORMAT_MATRIX_HTML; - } else { - Log.e(LOG_TAG, "Unsupported 'msgtype': " + msgType + ". Consider calling Room.canReplyTo(Event)"); - - // Ensure there will not be "m.relates_to" data in the sent event - roomMediaMessage.setReplyToEvent(null); - } - } else { - Log.e(LOG_TAG, "Null 'msgtype'. Consider calling Room.canReplyTo(Event)"); - - // Ensure there will not be "m.relates_to" data in the sent event - roomMediaMessage.setReplyToEvent(null); - } - } - - return message; - } - - private String includeReplyToToBody(Event replyToEvent, - String replyToBody, - boolean stripPreviousReplyTo, - String messageBody, - boolean isEmote) { - int firstLineIndex = 0; - - String[] lines = replyToBody.split("\n"); - - if (stripPreviousReplyTo) { - // Strip replyToBody from previous reply to - - // Strip line starting with "> " - while (firstLineIndex < lines.length && lines[firstLineIndex].startsWith("> ")) { - firstLineIndex++; - } - - // Strip empty line after - if (firstLineIndex < lines.length && lines[firstLineIndex].isEmpty()) { - firstLineIndex++; - } - } - - StringBuilder ret = new StringBuilder(); - - if (firstLineIndex < lines.length) { - // Add <${mxid}> to the first line - if (isEmote) { - lines[firstLineIndex] = "* <" + replyToEvent.sender + "> " + lines[firstLineIndex]; - } else { - lines[firstLineIndex] = "<" + replyToEvent.sender + "> " + lines[firstLineIndex]; - } - - for (int i = firstLineIndex; i < lines.length; i++) { - ret.append("> ") - .append(lines[i]) - .append("\n"); - } - } - - ret.append("\n") - .append(messageBody); - - return ret.toString(); - } - - private String includeReplyToToFormattedBody(Event replyToEvent, - String replyToFormattedBody, - boolean stripPreviousReplyTo, - String messageFormattedBody, - boolean isEmote) { - if (stripPreviousReplyTo) { - // Strip replyToFormattedBody from previous reply to - replyToFormattedBody = replyToFormattedBody.replaceAll("^.*", ""); - } - - StringBuilder ret = new StringBuilder("
") - // "In reply to" - .append(mContext.getString(R.string.message_reply_to_prefix)) - .append(" "); - - if (isEmote) { - ret.append("* "); - } - - ret.append("") - // ${mxid} - .append(replyToEvent.sender) - .append("
") - .append(replyToFormattedBody) - .append("
") - .append(messageFormattedBody); - - return ret.toString(); - } - - /** - * Returns the thumbnail path of shot image. - * - * @param picturePath the image path - * @return the thumbnail image path. - */ - private static String getThumbnailPath(String picturePath) { - if (!TextUtils.isEmpty(picturePath) && picturePath.endsWith(".jpg")) { - return picturePath.replace(".jpg", "_thumb.jpg"); - } - - return null; - } - - /** - * Retrieves the image thumbnail saved by the medias picker. - * - * @param sharedDataItem the sharedItem - * @return the thumbnail if it exits. - */ - private Bitmap getMediasPickerThumbnail(RoomMediaMessage sharedDataItem) { - Bitmap thumbnailBitmap = null; - - try { - String thumbPath = getThumbnailPath(sharedDataItem.getUri().getPath()); - - if (null != thumbPath) { - File thumbFile = new File(thumbPath); - - if (thumbFile.exists()) { - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inPreferredConfig = Bitmap.Config.ARGB_8888; - thumbnailBitmap = BitmapFactory.decodeFile(thumbPath, options); - } - } - } catch (Exception e) { - Log.e(LOG_TAG, "cannot restore the medias picker thumbnail " + e.getMessage(), e); - } catch (OutOfMemoryError oom) { - Log.e(LOG_TAG, "cannot restore the medias picker thumbnail oom", oom); - } - - return thumbnailBitmap; - } - - /** - * Retrieve the media Url. - * - * @param roomMediaMessage the room media message - * @return the media URL - */ - private String getMediaUrl(RoomMediaMessage roomMediaMessage) { - String mediaUrl = roomMediaMessage.getUri().toString(); - - if (!mediaUrl.startsWith("file:")) { - // save the content:// file in to the medias cache - String mimeType = roomMediaMessage.getMimeType(mContext); - ResourceUtils.Resource resource = ResourceUtils.openResource(mContext, roomMediaMessage.getUri(), mimeType); - - // save the file in the filesystem - mediaUrl = mDataHandler.getMediasCache().saveMedia(resource.mContentStream, null, mimeType); - resource.close(); - } - - return mediaUrl; - } - - /** - * Build an image message from a RoomMediaMessage. - * - * @param roomMediaMessage the roomMediaMessage - * @return the image message - */ - private Message buildImageMessage(RoomMediaMessage roomMediaMessage) { - try { - String mimeType = roomMediaMessage.getMimeType(mContext); - final MXMediasCache mediasCache = mDataHandler.getMediasCache(); - - String mediaUrl = getMediaUrl(roomMediaMessage); - - // compute the thumbnail - Bitmap thumbnailBitmap = roomMediaMessage.getFullScreenImageKindThumbnail(mContext); - - if (null == thumbnailBitmap) { - thumbnailBitmap = getMediasPickerThumbnail(roomMediaMessage); - } - - if (null == thumbnailBitmap) { - Pair thumbnailSize = roomMediaMessage.getThumbnailSize(); - thumbnailBitmap = ResourceUtils.createThumbnailBitmap(mContext, roomMediaMessage.getUri(), thumbnailSize.first, thumbnailSize.second); - } - - if (null == thumbnailBitmap) { - thumbnailBitmap = roomMediaMessage.getMiniKindImageThumbnail(mContext); - } - - String thumbnailURL = null; - - if (null != thumbnailBitmap) { - thumbnailURL = mediasCache.saveBitmap(thumbnailBitmap, null); - } - - // get the exif rotation angle - final int rotationAngle = ImageUtils.getRotationAngleForBitmap(mContext, Uri.parse(mediaUrl)); - - if (0 != rotationAngle) { - // always apply the rotation to the image - ImageUtils.rotateImage(mContext, thumbnailURL, rotationAngle, mediasCache); - } - - ImageMessage imageMessage = new ImageMessage(); - imageMessage.url = mediaUrl; - imageMessage.body = roomMediaMessage.getFileName(mContext); - - if (TextUtils.isEmpty(imageMessage.body)) { - imageMessage.body = "Image"; - } - - Uri imageUri = Uri.parse(mediaUrl); - - if (null == imageMessage.info) { - Room.fillImageInfo(mContext, imageMessage, imageUri, mimeType); - } - - if ((null != thumbnailURL) && (null != imageMessage.info) && (null == imageMessage.info.thumbnailInfo)) { - Uri thumbUri = Uri.parse(thumbnailURL); - Room.fillThumbnailInfo(mContext, imageMessage, thumbUri, "image/jpeg"); - imageMessage.info.thumbnailUrl = thumbnailURL; - } - - return imageMessage; - } catch (Exception e) { - Log.e(LOG_TAG, "## buildImageMessage() failed " + e.getMessage(), e); - } - - return null; - } - - /** - * Compute the video thumbnail - * - * @param videoUrl the video url - * @return the video thumbnail - */ - public String getVideoThumbnailUrl(final String videoUrl) { - String thumbUrl = null; - try { - Uri uri = Uri.parse(videoUrl); - Bitmap thumb = ThumbnailUtils.createVideoThumbnail(uri.getPath(), MediaStore.Images.Thumbnails.MINI_KIND); - thumbUrl = mDataHandler.getMediasCache().saveBitmap(thumb, null); - } catch (Exception e) { - Log.e(LOG_TAG, "## getVideoThumbnailUrl() failed with " + e.getMessage(), e); - } - - return thumbUrl; - } - - /** - * Build an video message from a RoomMediaMessage. - * - * @param roomMediaMessage the roomMediaMessage - * @return the video message - */ - private Message buildVideoMessage(RoomMediaMessage roomMediaMessage) { - try { - String mediaUrl = getMediaUrl(roomMediaMessage); - String thumbnailUrl = getVideoThumbnailUrl(mediaUrl); - - if (null == thumbnailUrl) { - return buildFileMessage(roomMediaMessage); - } - - VideoMessage videoMessage = new VideoMessage(); - videoMessage.url = mediaUrl; - videoMessage.body = roomMediaMessage.getFileName(mContext); - - Uri videoUri = Uri.parse(mediaUrl); - Uri thumbnailUri = (null != thumbnailUrl) ? Uri.parse(thumbnailUrl) : null; - Room.fillVideoInfo(mContext, videoMessage, videoUri, roomMediaMessage.getMimeType(mContext), thumbnailUri, "image/jpeg"); - - if (null == videoMessage.body) { - videoMessage.body = videoUri.getLastPathSegment(); - } - - return videoMessage; - } catch (Exception e) { - Log.e(LOG_TAG, "## buildVideoMessage() failed " + e.getMessage(), e); - } - - return null; - } - - /** - * Build an file message from a RoomMediaMessage. - * - * @param roomMediaMessage the roomMediaMessage - * @return the video message - */ - private Message buildFileMessage(RoomMediaMessage roomMediaMessage) { - try { - String mimeType = roomMediaMessage.getMimeType(mContext); - - String mediaUrl = getMediaUrl(roomMediaMessage); - FileMessage fileMessage; - - if (mimeType.startsWith("audio/")) { - fileMessage = new AudioMessage(); - } else { - fileMessage = new FileMessage(); - } - - fileMessage.url = mediaUrl; - fileMessage.body = roomMediaMessage.getFileName(mContext); - Uri uri = Uri.parse(mediaUrl); - Room.fillFileInfo(mContext, fileMessage, uri, mimeType); - - if (null == fileMessage.body) { - fileMessage.body = uri.getLastPathSegment(); - } - - return fileMessage; - } catch (Exception e) { - Log.e(LOG_TAG, "## buildFileMessage() failed " + e.getMessage(), e); - } - - return null; - } - - //============================================================================================================== - // Upload medias management - //============================================================================================================== - - /** - * Upload the medias. - * - * @param roomMediaMessage the roomMediaMessage - * @return true if a media is uploaded - */ - private boolean uploadMedias(final RoomMediaMessage roomMediaMessage) { - final Event event = roomMediaMessage.getEvent(); - final Message message = JsonUtils.toMessage(event.getContent()); - - if (!(message instanceof MediaMessage)) { - return false; - } - - final MediaMessage mediaMessage = (MediaMessage) message; - final String url; - final String fMimeType; - - if (mediaMessage.isThumbnailLocalContent()) { - url = mediaMessage.getThumbnailUrl(); - fMimeType = "image/jpeg"; - } else if (mediaMessage.isLocalContent()) { - url = mediaMessage.getUrl(); - fMimeType = mediaMessage.getMimeType(); - } else { - return false; - } - - mEncodingHandler.post(new Runnable() { - @Override - public void run() { - final MXMediasCache mediasCache = mDataHandler.getMediasCache(); - - Uri uri = Uri.parse(url); - String mimeType = fMimeType; - final MXEncryptedAttachments.EncryptionResult encryptionResult; - final Uri encryptedUri; - InputStream stream; - - String filename = null; - - try { - stream = new FileInputStream(new File(uri.getPath())); - if (mRoom.isEncrypted() && mDataHandler.isCryptoEnabled() && (null != stream)) { - encryptionResult = MXEncryptedAttachments.encryptAttachment(stream, mimeType); - stream.close(); - - if (null != encryptionResult) { - mimeType = "application/octet-stream"; - encryptedUri = Uri.parse(mediasCache.saveMedia(encryptionResult.mEncryptedStream, null, fMimeType)); - File file = new File(encryptedUri.getPath()); - stream = new FileInputStream(file); - } else { - skip(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - mDataHandler.updateEventState(roomMediaMessage.getEvent(), Event.SentState.UNDELIVERED); - mRoom.storeOutgoingEvent(roomMediaMessage.getEvent()); - mDataHandler.getStore().commit(); - - roomMediaMessage.onEncryptionFailed(); - } - }); - - return; - } - } else { - // Only pass filename string to server in non-encrypted rooms to prevent leaking filename - filename = mediaMessage.isThumbnailLocalContent() ? ("thumb" + message.body) : message.body; - encryptionResult = null; - encryptedUri = null; - } - } catch (Exception e) { - skip(); - return; - } - - mDataHandler.updateEventState(roomMediaMessage.getEvent(), Event.SentState.SENDING); - - mediasCache.uploadContent(stream, filename, mimeType, url, - new MXMediaUploadListener() { - @Override - public void onUploadStart(final String uploadId) { - mUiHandler.post(new Runnable() { - @Override - public void run() { - if (null != roomMediaMessage.getMediaUploadListener()) { - roomMediaMessage.getMediaUploadListener().onUploadStart(uploadId); - } - } - }); - } - - @Override - public void onUploadCancel(final String uploadId) { - mUiHandler.post(new Runnable() { - @Override - public void run() { - mDataHandler.updateEventState(roomMediaMessage.getEvent(), Event.SentState.UNDELIVERED); - - if (null != roomMediaMessage.getMediaUploadListener()) { - roomMediaMessage.getMediaUploadListener().onUploadCancel(uploadId); - roomMediaMessage.setMediaUploadListener(null); - roomMediaMessage.setEventSendingCallback(null); - } - - skip(); - } - }); - } - - @Override - public void onUploadError(final String uploadId, final int serverResponseCode, final String serverErrorMessage) { - mUiHandler.post(new Runnable() { - @Override - public void run() { - mDataHandler.updateEventState(roomMediaMessage.getEvent(), Event.SentState.UNDELIVERED); - - if (null != roomMediaMessage.getMediaUploadListener()) { - roomMediaMessage.getMediaUploadListener().onUploadError(uploadId, serverResponseCode, serverErrorMessage); - roomMediaMessage.setMediaUploadListener(null); - roomMediaMessage.setEventSendingCallback(null); - } - - skip(); - } - }); - } - - @Override - public void onUploadComplete(final String uploadId, final String contentUri) { - mUiHandler.post(new Runnable() { - @Override - public void run() { - boolean isThumbnailUpload = mediaMessage.isThumbnailLocalContent(); - - if (isThumbnailUpload) { - mediaMessage.setThumbnailUrl(encryptionResult, contentUri); - - if (null != encryptionResult) { - mediasCache.saveFileMediaForUrl(contentUri, encryptedUri.toString(), -1, -1, "image/jpeg"); - try { - new File(Uri.parse(url).getPath()).delete(); - } catch (Exception e) { - Log.e(LOG_TAG, "## cannot delete the uncompress media", e); - } - } else { - Pair thumbnailSize = roomMediaMessage.getThumbnailSize(); - mediasCache.saveFileMediaForUrl(contentUri, url, thumbnailSize.first, thumbnailSize.second, "image/jpeg"); - } - - // update the event content with the new message info - event.updateContent(JsonUtils.toJson(message)); - - // force to save the room events list - // https://github.com/vector-im/riot-android/issues/1390 - mDataHandler.getStore().flushRoomEvents(mRoom.getRoomId()); - - // upload the media - uploadMedias(roomMediaMessage); - } else { - if (null != encryptedUri) { - // replace the thumbnail and the media contents by the computed one - mediasCache.saveFileMediaForUrl(contentUri, encryptedUri.toString(), mediaMessage.getMimeType()); - try { - new File(Uri.parse(url).getPath()).delete(); - } catch (Exception e) { - Log.e(LOG_TAG, "## cannot delete the uncompress media", e); - } - } else { - // replace the thumbnail and the media contents by the computed one - mediasCache.saveFileMediaForUrl(contentUri, url, mediaMessage.getMimeType()); - } - mediaMessage.setUrl(encryptionResult, contentUri); - - // update the event content with the new message info - event.updateContent(JsonUtils.toJson(message)); - - // force to save the room events list - // https://github.com/vector-im/riot-android/issues/1390 - mDataHandler.getStore().flushRoomEvents(mRoom.getRoomId()); - - Log.d(LOG_TAG, "Uploaded to " + contentUri); - - // send - sendEvent(event); - } - - if (null != roomMediaMessage.getMediaUploadListener()) { - roomMediaMessage.getMediaUploadListener().onUploadComplete(uploadId, contentUri); - - if (!isThumbnailUpload) { - roomMediaMessage.setMediaUploadListener(null); - } - } - } - }); - } - }); - } - }); - - return true; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomPreviewData.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomPreviewData.java deleted file mode 100644 index 8c28e94b..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomPreviewData.java +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.data; - -import android.os.AsyncTask; -import android.os.Looper; -import android.support.annotation.Nullable; -import android.text.TextUtils; - -import im.vector.matrix.android.internal.legacy.MXSession; -import im.vector.matrix.android.internal.legacy.data.timeline.EventTimeline; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.rest.model.publicroom.PublicRoom; -import im.vector.matrix.android.internal.legacy.rest.model.sync.RoomResponse; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.util.Map; - -/** - * The `RoomEmailInvitation` gathers information for displaying the preview of a room that is unknown for the user. - * Such room can come from an email invitation link or a link to a room. - */ -public class RoomPreviewData { - - private static final String LOG_TAG = RoomPreviewData.class.getSimpleName(); - - // The id of the room to preview. - private String mRoomId; - - // the room Alias - private String mRoomAlias; - - // the id of the event to preview - private String mEventId; - - // In case of email invitation, the information extracted from the email invitation link. - private RoomEmailInvitation mRoomEmailInvitation; - - // preview information - // comes from the email invitation or retrieve from an initialSync - private String mRoomName; - private String mRoomAvatarUrl; - - // the room state - private RoomState mRoomState; - - // If the RoomState cannot be retrieved, this may contains some data - private PublicRoom mPublicRoom; - - // the initial sync data - private RoomResponse mRoomResponse; - - // the session - private MXSession mSession; - - /** - * Create an RoomPreviewData instance - * - * @param session the session. - * @param roomId the room Id to preview - * @param eventId the event Id to preview (optional) - * @param roomAlias the room alias (optional) - * @param emailInvitationParams the email invitation parameters (optional) - */ - public RoomPreviewData(MXSession session, String roomId, String eventId, String roomAlias, Map emailInvitationParams) { - mSession = session; - mRoomId = roomId; - mRoomAlias = roomAlias; - mEventId = eventId; - - if (null != emailInvitationParams) { - mRoomEmailInvitation = new RoomEmailInvitation(emailInvitationParams); - mRoomName = mRoomEmailInvitation.roomName; - mRoomAvatarUrl = mRoomEmailInvitation.roomAvatarUrl; - } - } - - /** - * @return the room state - */ - @Nullable - public RoomState getRoomState() { - return mRoomState; - } - - /** - * @return the public room data - */ - @Nullable - public PublicRoom getPublicRoom() { - return mPublicRoom; - } - - /** - * Update the room state. - * - * @param roomState the new roomstate - */ - public void setRoomState(RoomState roomState) { - mRoomState = roomState; - } - - /** - * @return the room name - */ - public String getRoomName() { - String roomName = mRoomName; - - if (TextUtils.isEmpty(roomName)) { - roomName = getRoomIdOrAlias(); - } - - return roomName; - } - - /** - * Set the room name. - * - * @param aRoomName the new room name - */ - public void setRoomName(String aRoomName) { - mRoomName = aRoomName; - } - - /** - * @return the room avatar URL - */ - public String getRoomAvatarUrl() { - return mRoomAvatarUrl; - } - - /** - * @return the room id - */ - public String getRoomId() { - return mRoomId; - } - - /** - * @return the room id or the alias (alias is preferred) - */ - public String getRoomIdOrAlias() { - if (!TextUtils.isEmpty(mRoomAlias)) { - return mRoomAlias; - } else { - return mRoomId; - } - } - - /** - * @return the event id. - */ - public String getEventId() { - return mEventId; - } - - /** - * @return the session - */ - public MXSession getSession() { - return mSession; - } - - /** - * @return the initial sync response - */ - public RoomResponse getRoomResponse() { - return mRoomResponse; - } - - /** - * @return the room invitation - */ - public RoomEmailInvitation getRoomEmailInvitation() { - return mRoomEmailInvitation; - } - - /** - * Attempt to get more information from the homeserver about the room. - * - * @param apiCallback the callback when the operation is done. - */ - public void fetchPreviewData(final ApiCallback apiCallback) { - mSession.getRoomsApiClient().initialSync(mRoomId, new ApiCallback() { - @Override - public void onSuccess(final RoomResponse roomResponse) { - AsyncTask task = new AsyncTask() { - @Override - protected Void doInBackground(Void... params) { - // save the initial sync response - mRoomResponse = roomResponse; - - mRoomState = new RoomState(); - mRoomState.roomId = mRoomId; - - for (Event event : roomResponse.state) { - mRoomState.applyState(null, event, EventTimeline.Direction.FORWARDS); - } - - // TODO LazyLoading handle case where room has no name - mRoomName = mRoomState.name; - mRoomAvatarUrl = mRoomState.getAvatarUrl(); - return null; - } - - @Override - protected void onPostExecute(Void args) { - apiCallback.onSuccess(null); - } - }; - try { - task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } catch (final Exception e) { - Log.e(LOG_TAG, "## fetchPreviewData() failed " + e.getMessage(), e); - task.cancel(true); - - (new android.os.Handler(Looper.getMainLooper())).post(new Runnable() { - @Override - public void run() { - if (null != apiCallback) { - apiCallback.onUnexpectedError(e); - } - } - }); - } - } - - @Override - public void onNetworkError(Exception e) { - mRoomState = new RoomState(); - mRoomState.roomId = mRoomId; - apiCallback.onNetworkError(e); - } - - @Override - public void onMatrixError(MatrixError e) { - mRoomState = new RoomState(); - mRoomState.roomId = mRoomId; - apiCallback.onMatrixError(e); - } - - @Override - public void onUnexpectedError(Exception e) { - mRoomState = new RoomState(); - mRoomState.roomId = mRoomId; - apiCallback.onUnexpectedError(e); - } - }); - } - - /** - * Set Public RoomData, In case RoomState cannot be retrieved - * - * @param publicRoom - */ - public void setPublicRoom(PublicRoom publicRoom) { - mPublicRoom = publicRoom; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomState.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomState.java deleted file mode 100644 index ce10ab52..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomState.java +++ /dev/null @@ -1,1334 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.data; - -import android.support.annotation.Nullable; -import android.text.TextUtils; - -import com.google.gson.JsonObject; - -import im.vector.matrix.android.internal.legacy.MXDataHandler; -import im.vector.matrix.android.internal.legacy.call.MXCallsManager; -import im.vector.matrix.android.internal.legacy.data.store.IMXStore; -import im.vector.matrix.android.internal.legacy.data.timeline.EventTimeline; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.SimpleApiCallback; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.PowerLevels; -import im.vector.matrix.android.internal.legacy.rest.model.RoomCreateContent; -import im.vector.matrix.android.internal.legacy.rest.model.RoomDirectoryVisibility; -import im.vector.matrix.android.internal.legacy.rest.model.RoomMember; -import im.vector.matrix.android.internal.legacy.rest.model.RoomPinnedEventsContent; -import im.vector.matrix.android.internal.legacy.rest.model.RoomTombstoneContent; -import im.vector.matrix.android.internal.legacy.rest.model.User; -import im.vector.matrix.android.internal.legacy.rest.model.pid.RoomThirdPartyInvite; -import im.vector.matrix.android.internal.legacy.util.JsonUtils; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.io.Externalizable; -import java.io.IOException; -import java.io.ObjectInput; -import java.io.ObjectOutput; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * The state of a room. - */ -public class RoomState implements Externalizable { - private static final String LOG_TAG = RoomState.class.getSimpleName(); - private static final long serialVersionUID = -6019932024524988201L; - - public static final String JOIN_RULE_PUBLIC = "public"; - public static final String JOIN_RULE_INVITE = "invite"; - - /** - * room access is granted to guests - */ - public static final String GUEST_ACCESS_CAN_JOIN = "can_join"; - /** - * room access is denied to guests - */ - public static final String GUEST_ACCESS_FORBIDDEN = "forbidden"; - - public static final String HISTORY_VISIBILITY_SHARED = "shared"; - public static final String HISTORY_VISIBILITY_INVITED = "invited"; - public static final String HISTORY_VISIBILITY_JOINED = "joined"; - public static final String HISTORY_VISIBILITY_WORLD_READABLE = "world_readable"; - - - // Public members used for JSON mapping - - // The room ID - public String roomId; - - // The power level of room members - private PowerLevels powerLevels; - - // The aliases - public List aliases; - - // The room aliases. The key is the domain. - private Map mRoomAliases = new HashMap<>(); - - // the aliases are defined for each home server url - private Map> mAliasesByDomain = new HashMap<>(); - - // merged from mAliasesByHomeServerUrl - private List mMergedAliasesList; - - // - private Map> mStateEvents = new HashMap<>(); - - // The canonical alias of the room. - private String canonicalAlias; - - // The name of the room as provided by the home server. - public String name; - - // The topic of the room. - public String topic; - - // The tombstone content if the room has been killed - private RoomTombstoneContent mRoomTombstoneContent; - - // The avatar url of the room. - public String url; - public String avatar_url; - - // the room create content - private RoomCreateContent mRoomCreateContent; - - // the room pinned events content - @Nullable - private RoomPinnedEventsContent mRoomPinnedEventsContent; - - // the join rule - public String join_rule; - - /** - * the guest access policy of the room - **/ - public String guest_access; - - // SPEC-134 - public String history_visibility; - - /** - * the room visibility in the directory list (i.e. public, private...) - **/ - public String visibility; - - // the encryption algorithm - public String algorithm; - - // group ids list which should be displayed - public List groups; - - /** - * The number of unread messages that match the push notification rules. - * It is based on the notificationCount field in /sync response. - */ - private int mNotificationCount; - - /** - * The number of highlighted unread messages (subset of notifications). - * It is based on the notificationCount field in /sync response. - */ - private int mHighlightCount; - - // the associated token - private String token; - - // the room members. May be a partial list if all members are not loaded yet, due to lazy loading - private final Map mMembers = new HashMap<>(); - - // true if all members are loaded - private boolean mAllMembersAreLoaded; - - private final List>> mGetAllMembersCallbacks = new ArrayList<>(); - - // the third party invite members - private final Map mThirdPartyInvites = new HashMap<>(); - - /** - * Cache for [self memberWithThirdPartyInviteToken]. - * The key is the 3pid invite token. - */ - private final Map mMembersWithThirdPartyInviteTokenCache = new HashMap<>(); - - /** - * Tell if the roomstate if a live one. - */ - private boolean mIsLive; - - // the unitary tests crash when MXDataHandler type is set. - // TODO Try to avoid this ^^ - private transient Object mDataHandler = null; - - // member display cache - private transient Map mMemberDisplayNameByUserId = new HashMap<>(); - - // get the guest access - // avoid the null case - public String getGuestAccess() { - if (null != guest_access) { - return guest_access; - } - - // retro compliancy - return RoomState.GUEST_ACCESS_FORBIDDEN; - } - - // get the history visibility - // avoid the null case - public String getHistoryVisibility() { - if (null != history_visibility) { - return history_visibility; - } - - // retro compliancy - return RoomState.HISTORY_VISIBILITY_SHARED; - } - - /** - * @return the state token - */ - public String getToken() { - return token; - } - - /** - * Update the token. - * - * @param token the new token - */ - public void setToken(String token) { - this.token = token; - } - - // avatar Url makes more sense than url. - public String getAvatarUrl() { - if (null != url) { - return url; - } else { - return avatar_url; - } - } - - /** - * @return the related group ids list (cannot be null) - */ - public List getRelatedGroups() { - return (null == groups) ? new ArrayList() : groups; - } - - /** - * @return a copy of the room members list. May be incomplete if the full list is not loaded yet - */ - public List getLoadedMembers() { - List res; - - synchronized (this) { - // make a copy to avoid concurrency modifications - res = new ArrayList<>(mMembers.values()); - } - - return res; - } - - /** - * Get the list of all the room members. Fetch from server if the full list is not loaded yet. - * - * @param callback The callback to get a copy of the room members list. - */ - public void getMembersAsync(ApiCallback> callback) { - if (areAllMembersLoaded()) { - List res; - - synchronized (this) { - // make a copy to avoid concurrency modifications - res = new ArrayList<>(mMembers.values()); - } - - callback.onSuccess(res); - } else { - boolean doTheRequest; - - synchronized (mGetAllMembersCallbacks) { - mGetAllMembersCallbacks.add(callback); - - doTheRequest = mGetAllMembersCallbacks.size() == 1; - } - - if (doTheRequest) { - // Load members from server - getDataHandler().getMembersAsync(roomId, new SimpleApiCallback>(callback) { - @Override - public void onSuccess(List info) { - Log.d(LOG_TAG, "getMembers has returned " + info.size() + " users."); - - IMXStore store = ((MXDataHandler) mDataHandler).getStore(); - List res; - - for (RoomMember member : info) { - // Do not erase already known members form the sync - if (getMember(member.getUserId()) == null) { - setMember(member.getUserId(), member); - - // Also create a User - if (store != null) { - store.updateUserWithRoomMemberEvent(member); - } - } - } - - synchronized (mGetAllMembersCallbacks) { - for (ApiCallback> apiCallback : mGetAllMembersCallbacks) { - // make a copy to avoid concurrency modifications - res = new ArrayList<>(mMembers.values()); - - apiCallback.onSuccess(res); - } - - mGetAllMembersCallbacks.clear(); - } - - mAllMembersAreLoaded = true; - } - }); - } - } - } - - /** - * Tell if all members has been loaded - * - * @return true if LazyLoading is Off, or if all members has been loaded - */ - private boolean areAllMembersLoaded() { - return mDataHandler != null - && (!((MXDataHandler) mDataHandler).isLazyLoadingEnabled() || mAllMembersAreLoaded); - } - - /** - * Force a fetch of the loaded members the next time they will be requested - */ - public void forceMembersRequest() { - mAllMembersAreLoaded = false; - } - - /** - * Provides the loaded states event list. - * The room member events are NOT included. - * - * @param types the allowed event types. - * @return the filtered state events list. - */ - public List getStateEvents(final Set types) { - final List filteredStateEvents = new ArrayList<>(); - final List stateEvents = new ArrayList<>(); - - // merge the values lists - Collection> currentStateEvents = mStateEvents.values(); - for (List eventsList : currentStateEvents) { - stateEvents.addAll(eventsList); - } - - if ((null != types) && !types.isEmpty()) { - for (Event stateEvent : stateEvents) { - if ((null != stateEvent.getType()) && types.contains(stateEvent.getType())) { - filteredStateEvents.add(stateEvent); - } - } - } else { - filteredStateEvents.addAll(stateEvents); - } - - return filteredStateEvents; - } - - - /** - * Provides the state events list. - * It includes the room member creation events (they are not loaded in memory by default). - * - * @param store the store in which the state events must be retrieved - * @param types the allowed event types. - * @param callback the asynchronous callback. - */ - public void getStateEvents(IMXStore store, final Set types, final ApiCallback> callback) { - /* if (null != store) { - final List stateEvents = new ArrayList<>(); - - Collection> currentStateEvents = mStateEvents.values(); - - for (List eventsList : currentStateEvents) { - stateEvents.addAll(eventsList); - } - - // retrieve the roomMember creation events - store.getRoomStateEvents(roomId, new SimpleApiCallback>() { - @Override - public void onSuccess(List events) { - stateEvents.addAll(events); - - final List filteredStateEvents = new ArrayList<>(); - - if ((null != types) && !types.isEmpty()) { - for (Event stateEvent : stateEvents) { - if ((null != stateEvent.getType()) && types.contains(stateEvent.getType())) { - filteredStateEvents.add(stateEvent); - } - } - } else { - filteredStateEvents.addAll(stateEvents); - } - - callback.onSuccess(filteredStateEvents); - } - }); - }*/ - } - - /** - * @return a copy of the displayable members list. May be incomplete if the full list is not loaded yet - */ - public List getDisplayableLoadedMembers() { - List res = getLoadedMembers(); - - RoomMember conferenceUserId = getMember(MXCallsManager.getConferenceUserId(roomId)); - - if (null != conferenceUserId) { - res.remove(conferenceUserId); - } - - return res; - } - - /** - * Provides a list of displayable members. - * Some dummy members are created to internal stuff. - * - * @param callback The callback to get a copy of the displayable room members list. - */ - public void getDisplayableMembersAsync(final ApiCallback> callback) { - getMembersAsync(new SimpleApiCallback>(callback) { - @Override - public void onSuccess(List members) { - RoomMember conferenceUserId = getMember(MXCallsManager.getConferenceUserId(roomId)); - - if (null != conferenceUserId) { - List membersList = new ArrayList<>(members); - membersList.remove(conferenceUserId); - callback.onSuccess(membersList); - } else { - callback.onSuccess(members); - } - } - }); - } - - /** - * Tells if the room is a call conference one - * i.e. this room has been created to manage the call conference - * - * @return true if it is a call conference room. - */ - public boolean isConferenceUserRoom() { - return getDataHandler().getStore().getSummary(roomId).isConferenceUserRoom(); - } - - /** - * Set this room as a conference user room - * - * @param isConferenceUserRoom true when it is an user conference room. - */ - public void setIsConferenceUserRoom(boolean isConferenceUserRoom) { - getDataHandler().getStore().getSummary(roomId).setIsConferenceUserRoom(isConferenceUserRoom); - } - - /** - * Update the room member from its user id. - * - * @param userId the user id. - * @param member the new member value. - */ - private void setMember(String userId, RoomMember member) { - // Populate a basic user object if there is none - if (member.getUserId() == null) { - member.setUserId(userId); - } - synchronized (this) { - if (null != mMemberDisplayNameByUserId) { - mMemberDisplayNameByUserId.remove(userId); - } - mMembers.put(userId, member); - } - } - - /** - * Retrieve a room member from its user id. - * - * @param userId the user id. - * @return the linked member it exists. - */ - // TODO Change this? Can return null if all members are not loaded yet - @Nullable - public RoomMember getMember(String userId) { - RoomMember member; - - synchronized (this) { - member = mMembers.get(userId); - } - - if (member == null) { - // TODO LazyLoading - Log.e(LOG_TAG, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Null member '" + userId + "' !!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); - - if (TextUtils.equals(getDataHandler().getUserId(), userId)) { - // This should never happen - Log.e(LOG_TAG, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Null current user '" + userId + "' !!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); - } - } - - return member; - } - - /** - * Retrieve a room member from its original event id. - * It can return null if the lazy loading is enabled and if the member is not loaded yet. - * - * @param eventId the event id. - * @return the linked member if it exists and if it is loaded. - */ - @Nullable - public RoomMember getMemberByEventId(String eventId) { - RoomMember member = null; - - synchronized (this) { - for (RoomMember aMember : mMembers.values()) { - if (aMember.getOriginalEventId().equals(eventId)) { - member = aMember; - break; - } - } - } - - return member; - } - - /** - * Remove a member defines by its user id. - * - * @param userId the user id. - */ - public void removeMember(String userId) { - synchronized (this) { - mMembers.remove(userId); - // remove the cached display name - if (null != mMemberDisplayNameByUserId) { - mMemberDisplayNameByUserId.remove(userId); - } - } - } - - /** - * Retrieve a member from an invitation token. - * - * @param thirdPartyInviteToken the third party invitation token. - * @return the member it exists. - */ - public RoomMember memberWithThirdPartyInviteToken(String thirdPartyInviteToken) { - return mMembersWithThirdPartyInviteTokenCache.get(thirdPartyInviteToken); - } - - /** - * Retrieve a RoomThirdPartyInvite from its token. - * - * @param thirdPartyInviteToken the third party invitation token. - * @return the linked RoomThirdPartyInvite if it exists - */ - public RoomThirdPartyInvite thirdPartyInviteWithToken(String thirdPartyInviteToken) { - return mThirdPartyInvites.get(thirdPartyInviteToken); - } - - /** - * @return the third party invite list. - */ - public Collection thirdPartyInvites() { - return mThirdPartyInvites.values(); - } - - /** - * @return the power levels (it can be null). - */ - public PowerLevels getPowerLevels() { - if (null != powerLevels) { - return powerLevels.deepCopy(); - } else { - return null; - } - } - - /** - * Update the power levels. - * - * @param powerLevels the new power levels - */ - public void setPowerLevels(PowerLevels powerLevels) { - this.powerLevels = powerLevels; - } - - /** - * Update the linked dataHandler. - * - * @param dataHandler the new dataHandler - */ - public void setDataHandler(MXDataHandler dataHandler) { - mDataHandler = dataHandler; - } - - /** - * @return the user dataHandler - */ - public MXDataHandler getDataHandler() { - return (MXDataHandler) mDataHandler; - } - - /** - * Update the notified messages count. - * - * @param notificationCount the new notified messages count. - */ - public void setNotificationCount(int notificationCount) { - Log.d(LOG_TAG, "## setNotificationCount() : " + notificationCount + " room id " + roomId); - mNotificationCount = notificationCount; - } - - /** - * @return the notified messages count. - */ - public int getNotificationCount() { - return mNotificationCount; - } - - /** - * Update the highlighted messages count. - * - * @param highlightCount the new highlighted messages count. - */ - public void setHighlightCount(int highlightCount) { - Log.d(LOG_TAG, "## setHighlightCount() : " + highlightCount + " room id " + roomId); - mHighlightCount = highlightCount; - } - - /** - * @return the highlighted messages count. - */ - public int getHighlightCount() { - return mHighlightCount; - } - - /** - * Check if the user userId can back paginate. - * - * @param isJoined true is user is in the room - * @param isInvited true is user is invited to the room - * @return true if the user can back paginate. - */ - public boolean canBackPaginate(boolean isJoined, boolean isInvited) { - String visibility = TextUtils.isEmpty(history_visibility) ? HISTORY_VISIBILITY_SHARED : history_visibility; - - return isJoined - || visibility.equals(HISTORY_VISIBILITY_WORLD_READABLE) - || visibility.equals(HISTORY_VISIBILITY_SHARED) - || (visibility.equals(HISTORY_VISIBILITY_INVITED) && isInvited); - } - - /** - * Make a deep copy of this room state object. - * - * @return the copy - */ - public RoomState deepCopy() { - RoomState copy = new RoomState(); - copy.roomId = roomId; - copy.setPowerLevels((powerLevels == null) ? null : powerLevels.deepCopy()); - copy.aliases = (aliases == null) ? null : new ArrayList<>(aliases); - copy.mAliasesByDomain = new HashMap<>(mAliasesByDomain); - copy.canonicalAlias = canonicalAlias; - copy.name = name; - copy.topic = topic; - copy.url = url; - copy.mRoomCreateContent = mRoomCreateContent != null ? mRoomCreateContent.deepCopy() : null; - copy.mRoomPinnedEventsContent = mRoomPinnedEventsContent != null ? mRoomPinnedEventsContent.deepCopy() : null; - copy.join_rule = join_rule; - copy.guest_access = guest_access; - copy.history_visibility = history_visibility; - copy.visibility = visibility; - copy.token = token; - copy.groups = groups; - copy.mDataHandler = mDataHandler; - copy.mIsLive = mIsLive; - copy.mAllMembersAreLoaded = mAllMembersAreLoaded; - copy.algorithm = algorithm; - copy.mRoomAliases = new HashMap<>(mRoomAliases); - copy.mStateEvents = new HashMap<>(mStateEvents); - copy.mRoomTombstoneContent = mRoomTombstoneContent != null ? mRoomTombstoneContent.deepCopy() : null; - synchronized (this) { - Iterator it = mMembers.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry pair = (Map.Entry) it.next(); - copy.setMember(pair.getKey(), pair.getValue().deepCopy()); - } - - Collection keys = mThirdPartyInvites.keySet(); - for (String key : keys) { - copy.mThirdPartyInvites.put(key, mThirdPartyInvites.get(key).deepCopy()); - } - - keys = mMembersWithThirdPartyInviteTokenCache.keySet(); - for (String key : keys) { - copy.mMembersWithThirdPartyInviteTokenCache.put(key, mMembersWithThirdPartyInviteTokenCache.get(key).deepCopy()); - } - } - - return copy; - } - - /** - * @return the room canonical alias - */ - public String getCanonicalAlias() { - return canonicalAlias; - } - - /** - * Update the canonical alias of a room - * - * @param newCanonicalAlias the new canonical alias - */ - public void setCanonicalAlias(String newCanonicalAlias) { - canonicalAlias = newCanonicalAlias; - } - - /** - * Provides the aliases for any known domains - * - * @return the aliases list - */ - public List getAliases() { - if (null == mMergedAliasesList) { - mMergedAliasesList = new ArrayList<>(); - - for (String url : mAliasesByDomain.keySet()) { - mMergedAliasesList.addAll(mAliasesByDomain.get(url)); - } - - // ensure that the current aliases have been added. - // for example for the public rooms because there is no applystate call. - if (null != aliases) { - for (String anAlias : aliases) { - if (mMergedAliasesList.indexOf(anAlias) < 0) { - mMergedAliasesList.add(anAlias); - } - } - } - } - - return mMergedAliasesList; - } - - /** - * Provides the aliases by domain - * - * @return the aliases list map - */ - public Map> getAliasesByDomain() { - return new HashMap<>(mAliasesByDomain); - } - - /** - * Remove an alias. - * - * @param alias the alias to remove - */ - public void removeAlias(String alias) { - if (getAliases().indexOf(alias) >= 0) { - if (null != aliases) { - aliases.remove(alias); - } - - for (String host : mAliasesByDomain.keySet()) { - mAliasesByDomain.get(host).remove(alias); - } - - mMergedAliasesList = null; - } - } - - /** - * Add an alias. - * - * @param alias the alias to add - */ - public void addAlias(String alias) { - if (getAliases().indexOf(alias) < 0) { - // patch until the server echoes the alias addition. - mMergedAliasesList.add(alias); - } - } - - /** - * @return true if the room is encrypted - */ - public boolean isEncrypted() { - // When a client receives an m.room.encryption event as above, it should set a flag to indicate that messages sent in the room should be encrypted. - // This flag should not be cleared if a later m.room.encryption event changes the configuration. This is to avoid a situation where a MITM can simply - // ask participants to disable encryption. In short: once encryption is enabled in a room, it can never be disabled. - return null != algorithm; - } - - /** - * @return true if the room is versioned, it means that the room is obsolete. - * You can't interact with it anymore, but you can still browse the past messages. - */ - public boolean isVersioned() { - return mRoomTombstoneContent != null; - } - - /** - * @return the room tombstone content - */ - public RoomTombstoneContent getRoomTombstoneContent() { - return mRoomTombstoneContent; - } - - /** - * @return true if the room has a predecessor - */ - public boolean hasPredecessor() { - return mRoomCreateContent != null && mRoomCreateContent.hasPredecessor(); - } - - /** - * @return the room create content - */ - public RoomCreateContent getRoomCreateContent() { - return mRoomCreateContent; - } - - /** - * @return the room pinned events content - */ - @Nullable - public RoomPinnedEventsContent getRoomPinnedEventsContent() { - return mRoomPinnedEventsContent; - } - - /** - * @return the encryption algorithm - */ - public String encryptionAlgorithm() { - return TextUtils.isEmpty(algorithm) ? null : algorithm; - } - - /** - * Apply the given event (relevant for state changes) to our state. - * - * @param store the store to use - * @param event the event - * @param direction how the event should affect the state: Forwards for applying, backwards for un-applying (applying the previous state) - * @return true if the event is managed - */ - public boolean applyState(IMXStore store, Event event, EventTimeline.Direction direction) { - if (event.stateKey == null) { - return false; - } - - JsonObject contentToConsider = (direction == EventTimeline.Direction.FORWARDS) ? event.getContentAsJsonObject() : event.getPrevContentAsJsonObject(); - String eventType = event.getType(); - - try { - if (Event.EVENT_TYPE_STATE_ROOM_NAME.equals(eventType)) { - name = JsonUtils.toStateEvent(contentToConsider).name; - } else if (Event.EVENT_TYPE_STATE_ROOM_TOPIC.equals(eventType)) { - topic = JsonUtils.toStateEvent(contentToConsider).topic; - } else if (Event.EVENT_TYPE_STATE_ROOM_CREATE.equals(eventType)) { - mRoomCreateContent = JsonUtils.toRoomCreateContent(contentToConsider); - } else if (Event.EVENT_TYPE_STATE_ROOM_JOIN_RULES.equals(eventType)) { - join_rule = JsonUtils.toStateEvent(contentToConsider).joinRule; - } else if (Event.EVENT_TYPE_STATE_ROOM_GUEST_ACCESS.equals(eventType)) { - guest_access = JsonUtils.toStateEvent(contentToConsider).guestAccess; - } else if (Event.EVENT_TYPE_STATE_ROOM_ALIASES.equals(eventType)) { - if (!TextUtils.isEmpty(event.stateKey)) { - // backward compatibility - aliases = JsonUtils.toStateEvent(contentToConsider).aliases; - - // sanity check - if (null != aliases) { - mAliasesByDomain.put(event.stateKey, aliases); - mRoomAliases.put(event.stateKey, event); - } else { - mAliasesByDomain.put(event.stateKey, new ArrayList()); - } - } - } else if (Event.EVENT_TYPE_MESSAGE_ENCRYPTION.equals(eventType)) { - algorithm = JsonUtils.toStateEvent(contentToConsider).algorithm; - - // When a client receives an m.room.encryption event as above, it should set a flag to indicate that messages sent - // in the room should be encrypted. - // This flag should not be cleared if a later m.room.encryption event changes the configuration. This is to avoid - // a situation where a MITM can simply ask participants to disable encryption. In short: once encryption is enabled - // in a room, it can never be disabled. - if (null == algorithm) { - algorithm = ""; - } - } else if (Event.EVENT_TYPE_STATE_CANONICAL_ALIAS.equals(eventType)) { - // SPEC-125 - canonicalAlias = JsonUtils.toStateEvent(contentToConsider).canonicalAlias; - } else if (Event.EVENT_TYPE_STATE_HISTORY_VISIBILITY.equals(eventType)) { - // SPEC-134 - history_visibility = JsonUtils.toStateEvent(contentToConsider).historyVisibility; - } else if (Event.EVENT_TYPE_STATE_ROOM_AVATAR.equals(eventType)) { - url = JsonUtils.toStateEvent(contentToConsider).url; - } else if (Event.EVENT_TYPE_STATE_RELATED_GROUPS.equals(eventType)) { - groups = JsonUtils.toStateEvent(contentToConsider).groups; - } else if (Event.EVENT_TYPE_STATE_ROOM_MEMBER.equals(eventType)) { - RoomMember member = JsonUtils.toRoomMember(contentToConsider); - String userId = event.stateKey; - - if (null == userId) { - Log.e(LOG_TAG, "## applyState() : null stateKey in " + roomId); - } else if (null == member) { - // the member has already been removed - if (null == getMember(userId)) { - Log.e(LOG_TAG, "## applyState() : the user " + userId + " is not anymore a member of " + roomId); - return false; - } - removeMember(userId); - } else { - try { - member.setUserId(userId); - member.setOriginServerTs(event.getOriginServerTs()); - member.setOriginalEventId(event.eventId); - member.mSender = event.getSender(); - - if ((null != store) && (direction == EventTimeline.Direction.FORWARDS)) { - //store.storeRoomStateEvent(roomId, event); - } - - RoomMember currentMember = getMember(userId); - - // check if the member is the same - // duplicated message ? - if (member.equals(currentMember)) { - Log.e(LOG_TAG, "## applyState() : seems being a duplicated event for " + userId + " in room " + roomId); - return false; - } - - // when a member leaves a room, his avatar / display name is not anymore provided - if (null != currentMember) { - if (TextUtils.equals(member.membership, RoomMember.MEMBERSHIP_LEAVE) - || TextUtils.equals(member.membership, (RoomMember.MEMBERSHIP_BAN))) { - if (null == member.getAvatarUrl()) { - member.setAvatarUrl(currentMember.getAvatarUrl()); - } - - if (null == member.displayname) { - member.displayname = currentMember.displayname; - } - - // remove the cached display name - if (null != mMemberDisplayNameByUserId) { - mMemberDisplayNameByUserId.remove(userId); - } - - // test if the user has been kicked - if (!TextUtils.equals(event.getSender(), event.stateKey) - && TextUtils.equals(currentMember.membership, RoomMember.MEMBERSHIP_JOIN) - && TextUtils.equals(member.membership, RoomMember.MEMBERSHIP_LEAVE)) { - member.membership = RoomMember.MEMBERSHIP_KICK; - } - } - } - - if ((direction == EventTimeline.Direction.FORWARDS) && (null != store)) { - store.updateUserWithRoomMemberEvent(member); - } - - // Cache room member event that is successor of a third party invite event - if (!TextUtils.isEmpty(member.getThirdPartyInviteToken())) { - mMembersWithThirdPartyInviteTokenCache.put(member.getThirdPartyInviteToken(), member); - } - } catch (Exception e) { - Log.e(LOG_TAG, "## applyState() - EVENT_TYPE_STATE_ROOM_MEMBER failed " + e.getMessage(), e); - } - - setMember(userId, member); - } - } else if (Event.EVENT_TYPE_STATE_ROOM_POWER_LEVELS.equals(eventType)) { - powerLevels = JsonUtils.toPowerLevels(contentToConsider); - } else if (Event.EVENT_TYPE_STATE_ROOM_THIRD_PARTY_INVITE.equals(event.getType())) { - if (null != contentToConsider) { - RoomThirdPartyInvite thirdPartyInvite = JsonUtils.toRoomThirdPartyInvite(contentToConsider); - - thirdPartyInvite.token = event.stateKey; - - if ((direction == EventTimeline.Direction.FORWARDS) && (null != store)) { - //store.storeRoomStateEvent(roomId, event); - } - - if (!TextUtils.isEmpty(thirdPartyInvite.token)) { - mThirdPartyInvites.put(thirdPartyInvite.token, thirdPartyInvite); - } - } - } else if (Event.EVENT_TYPE_STATE_ROOM_TOMBSTONE.equals(eventType)) { - mRoomTombstoneContent = JsonUtils.toRoomTombstoneContent(contentToConsider); - } else if (Event.EVENT_TYPE_STATE_PINNED_EVENT.equals(eventType)) { - mRoomPinnedEventsContent = JsonUtils.toRoomPinnedEventsContent(contentToConsider); - } - // same the latest room state events - // excepts the membership ones - // they are saved elsewhere - if (!TextUtils.isEmpty(eventType) && !Event.EVENT_TYPE_STATE_ROOM_MEMBER.equals(eventType)) { - List eventsList = mStateEvents.get(eventType); - - if (null == eventsList) { - eventsList = new ArrayList<>(); - mStateEvents.put(eventType, eventsList); - } - - eventsList.add(event); - } - - } catch (Exception e) { - Log.e(LOG_TAG, "applyState failed with error " + e.getMessage(), e); - } - - return true; - } - - /** - * @return true if the room is a public one - */ - public boolean isPublic() { - return TextUtils.equals((null != visibility) ? visibility : join_rule, RoomDirectoryVisibility.DIRECTORY_VISIBILITY_PUBLIC); - } - - /** - * Return an unique display name of the member userId. - * - * @param userId the user id - * @return unique display name - */ - public String getMemberName(String userId) { - // sanity check - if (null == userId) { - return null; - } - - String displayName; - - synchronized (this) { - if (null == mMemberDisplayNameByUserId) { - mMemberDisplayNameByUserId = new HashMap<>(); - } - displayName = mMemberDisplayNameByUserId.get(userId); - } - - if (null != displayName) { - return displayName; - } - - // Get the user display name from the member list of the room - RoomMember member = getMember(userId); - - // Do not consider null display name - if ((null != member) && !TextUtils.isEmpty(member.displayname)) { - displayName = member.displayname; - - synchronized (this) { - List matrixIds = new ArrayList<>(); - - // Disambiguate users who have the same display name in the room - for (RoomMember aMember : mMembers.values()) { - if (displayName.equals(aMember.displayname)) { - matrixIds.add(aMember.getUserId()); - } - } - - // if several users have the same display name - // index it i.e bob () - if (matrixIds.size() > 1) { - displayName += " (" + userId + ")"; - } - } - } else if ((null != member) && TextUtils.equals(member.membership, RoomMember.MEMBERSHIP_INVITE)) { - User user = ((MXDataHandler) mDataHandler).getUser(userId); - - if (null != user) { - displayName = user.displayname; - } - } - - if (null == displayName) { - // By default, use the user ID - displayName = userId; - } - - mMemberDisplayNameByUserId.put(userId, displayName); - - return displayName; - } - - @Override - public void readExternal(ObjectInput input) throws IOException, ClassNotFoundException { - if (input.readBoolean()) { - roomId = input.readUTF(); - } - - if (input.readBoolean()) { - powerLevels = (PowerLevels) input.readObject(); - } - - if (input.readBoolean()) { - aliases = (List) input.readObject(); - } - - List roomAliasesEvents = (List) input.readObject(); - for (Event e : roomAliasesEvents) { - mRoomAliases.put(e.stateKey, e); - } - - mAliasesByDomain = (Map>) input.readObject(); - - if (input.readBoolean()) { - mMergedAliasesList = (List) input.readObject(); - } - - Map> stateEvents = (Map>) input.readObject(); - if (null != stateEvents) { - mStateEvents = new HashMap<>(stateEvents); - } - - if (input.readBoolean()) { - canonicalAlias = input.readUTF(); - } - - if (input.readBoolean()) { - name = input.readUTF(); - } - - if (input.readBoolean()) { - topic = input.readUTF(); - } - - if (input.readBoolean()) { - url = input.readUTF(); - } - - if (input.readBoolean()) { - avatar_url = input.readUTF(); - } - - if (input.readBoolean()) { - mRoomCreateContent = (RoomCreateContent) input.readObject(); - } - - if (input.readBoolean()) { - mRoomPinnedEventsContent = (RoomPinnedEventsContent) input.readObject(); - } - - if (input.readBoolean()) { - join_rule = input.readUTF(); - } - - if (input.readBoolean()) { - guest_access = input.readUTF(); - } - - if (input.readBoolean()) { - history_visibility = input.readUTF(); - } - - if (input.readBoolean()) { - visibility = input.readUTF(); - } - - if (input.readBoolean()) { - algorithm = input.readUTF(); - } - - mNotificationCount = input.readInt(); - mHighlightCount = input.readInt(); - - if (input.readBoolean()) { - token = input.readUTF(); - } - - List members = (List) input.readObject(); - for (RoomMember r : members) { - mMembers.put(r.getUserId(), r); - } - - List invites = (List) input.readObject(); - for (RoomThirdPartyInvite i : invites) { - mThirdPartyInvites.put(i.token, i); - } - - List inviteTokens = (List) input.readObject(); - for (RoomMember r : inviteTokens) { - mMembersWithThirdPartyInviteTokenCache.put(r.getThirdPartyInviteToken(), r); - } - - mIsLive = input.readBoolean(); - - mAllMembersAreLoaded = input.readBoolean(); - - if (input.readBoolean()) { - groups = (List) input.readObject(); - } - - if (input.readBoolean()) { - mRoomTombstoneContent = (RoomTombstoneContent) input.readObject(); - } - } - - @Override - public void writeExternal(ObjectOutput output) throws IOException { - output.writeBoolean(null != roomId); - if (null != roomId) { - output.writeUTF(roomId); - } - - output.writeBoolean(null != powerLevels); - if (null != powerLevels) { - output.writeObject(powerLevels); - } - - output.writeBoolean(null != aliases); - if (null != aliases) { - output.writeObject(aliases); - } - - output.writeObject(new ArrayList<>(mRoomAliases.values())); - - output.writeObject(mAliasesByDomain); - - output.writeBoolean(null != mMergedAliasesList); - if (null != mMergedAliasesList) { - output.writeObject(mMergedAliasesList); - } - - output.writeObject(mStateEvents); - - output.writeBoolean(null != canonicalAlias); - if (null != canonicalAlias) { - output.writeUTF(canonicalAlias); - } - - output.writeBoolean(null != name); - if (null != name) { - output.writeUTF(name); - } - - output.writeBoolean(null != topic); - if (null != topic) { - output.writeUTF(topic); - } - - output.writeBoolean(null != url); - if (null != url) { - output.writeUTF(url); - } - - output.writeBoolean(null != avatar_url); - if (null != avatar_url) { - output.writeUTF(avatar_url); - } - - output.writeBoolean(null != mRoomCreateContent); - if (null != mRoomCreateContent) { - output.writeObject(mRoomCreateContent); - } - - output.writeBoolean(null != mRoomPinnedEventsContent); - if (null != mRoomPinnedEventsContent) { - output.writeObject(mRoomPinnedEventsContent); - } - - output.writeBoolean(null != join_rule); - if (null != join_rule) { - output.writeUTF(join_rule); - } - - output.writeBoolean(null != guest_access); - if (null != guest_access) { - output.writeUTF(guest_access); - } - - output.writeBoolean(null != history_visibility); - if (null != history_visibility) { - output.writeUTF(history_visibility); - } - - output.writeBoolean(null != visibility); - if (null != visibility) { - output.writeUTF(visibility); - } - - output.writeBoolean(null != algorithm); - if (null != algorithm) { - output.writeUTF(algorithm); - } - - output.writeInt(mNotificationCount); - output.writeInt(mHighlightCount); - - output.writeBoolean(null != token); - if (null != token) { - output.writeUTF(token); - } - - output.writeObject(new ArrayList<>(mMembers.values())); - output.writeObject(new ArrayList<>(mThirdPartyInvites.values())); - output.writeObject(new ArrayList<>(mMembersWithThirdPartyInviteTokenCache.values())); - - output.writeBoolean(mIsLive); - - output.writeBoolean(mAllMembersAreLoaded); - - output.writeBoolean(null != groups); - if (null != groups) { - output.writeObject(groups); - } - - output.writeBoolean(null != mRoomTombstoneContent); - if (null != mRoomTombstoneContent) { - output.writeObject(mRoomTombstoneContent); - } - } -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomSummary.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomSummary.java deleted file mode 100644 index 51a9521e..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomSummary.java +++ /dev/null @@ -1,593 +0,0 @@ -/* - * Copyright 2015 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.data; - -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.text.TextUtils; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; - -import im.vector.matrix.android.internal.legacy.call.MXCallsManager; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.EventContent; -import im.vector.matrix.android.internal.legacy.rest.model.RoomMember; -import im.vector.matrix.android.internal.legacy.rest.model.message.Message; -import im.vector.matrix.android.internal.legacy.rest.model.sync.RoomSyncSummary; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * Stores summarised information about the room. - */ -public class RoomSummary implements java.io.Serializable { - private static final String LOG_TAG = RoomSummary.class.getSimpleName(); - - private static final long serialVersionUID = -3683013938626566489L; - - // list of supported types - private static final List sSupportedType = Arrays.asList( - Event.EVENT_TYPE_STATE_ROOM_TOPIC, - Event.EVENT_TYPE_MESSAGE_ENCRYPTED, - Event.EVENT_TYPE_MESSAGE_ENCRYPTION, - Event.EVENT_TYPE_STATE_ROOM_NAME, - Event.EVENT_TYPE_STATE_ROOM_MEMBER, - Event.EVENT_TYPE_STATE_ROOM_CREATE, - Event.EVENT_TYPE_STATE_HISTORY_VISIBILITY, - Event.EVENT_TYPE_STATE_ROOM_THIRD_PARTY_INVITE, - Event.EVENT_TYPE_STICKER); - - // List of known unsupported types - private static final List sKnownUnsupportedType = Arrays.asList( - Event.EVENT_TYPE_TYPING, - Event.EVENT_TYPE_STATE_ROOM_POWER_LEVELS, - Event.EVENT_TYPE_STATE_ROOM_JOIN_RULES, - Event.EVENT_TYPE_STATE_CANONICAL_ALIAS, - Event.EVENT_TYPE_STATE_ROOM_ALIASES, - Event.EVENT_TYPE_URL_PREVIEW, - Event.EVENT_TYPE_STATE_RELATED_GROUPS, - Event.EVENT_TYPE_STATE_ROOM_GUEST_ACCESS, - Event.EVENT_TYPE_REDACTION); - - private String mRoomId = null; - private String mTopic = null; - private Event mLatestReceivedEvent = null; - - // the room state is only used to check - // 1- the invitation status - // 2- the members display name - private transient RoomState mLatestRoomState = null; - - // defines the latest read message - private String mReadReceiptEventId; - - // the read marker event id - private String mReadMarkerEventId; - - private Set mRoomTags; - - // counters - public int mUnreadEventsCount; - public int mNotificationCount; - public int mHighlightsCount; - - // invitation status - // retrieved at initial sync - // the roomstate is not always known - private String mInviterUserId = null; - - // retrieved from the roomState - private String mInviterName = null; - - private String mUserId = null; - - // Info from sync, depending on the room position in the sync - private String mUserMembership; - - /** - * Tell if the room is a user conference user one - */ - private Boolean mIsConferenceUserRoom = null; - - /** - * Data from RoomSyncSummary - */ - private List mHeroes = new ArrayList<>(); - - private int mJoinedMembersCountFromSyncRoomSummary; - - private int mInvitedMembersCountFromSyncRoomSummary; - - public RoomSummary() { - } - - /** - * Create a room summary - * - * @param fromSummary the summary source - * @param event the latest event of the room - * @param roomState the room state - used to display the event - * @param userId our own user id - used to display the room name - */ - public RoomSummary(@Nullable RoomSummary fromSummary, - Event event, - RoomState roomState, - String userId) { - mUserId = userId; - - if (null != roomState) { - setRoomId(roomState.roomId); - } - - if ((null == getRoomId()) && (null != event)) { - setRoomId(event.roomId); - } - - setLatestReceivedEvent(event, roomState); - - // if no summary is provided - if (null == fromSummary) { - if (null != event) { - setReadMarkerEventId(event.eventId); - setReadReceiptEventId(event.eventId); - } - - if (null != roomState) { - setHighlightCount(roomState.getHighlightCount()); - setNotificationCount(roomState.getHighlightCount()); - } - setUnreadEventsCount(Math.max(getHighlightCount(), getNotificationCount())); - } else { - // else use the provided summary data - setReadMarkerEventId(fromSummary.getReadMarkerEventId()); - setReadReceiptEventId(fromSummary.getReadReceiptEventId()); - setUnreadEventsCount(fromSummary.getUnreadEventsCount()); - setHighlightCount(fromSummary.getHighlightCount()); - setNotificationCount(fromSummary.getNotificationCount()); - - mHeroes.addAll(fromSummary.mHeroes); - mJoinedMembersCountFromSyncRoomSummary = fromSummary.mJoinedMembersCountFromSyncRoomSummary; - mInvitedMembersCountFromSyncRoomSummary = fromSummary.mInvitedMembersCountFromSyncRoomSummary; - - mUserMembership = fromSummary.mUserMembership; - } - } - - /** - * Test if the event can be summarized. - * Some event types are not yet supported. - * - * @param event the event to test. - * @return true if the event can be summarized - */ - public static boolean isSupportedEvent(Event event) { - String type = event.getType(); - boolean isSupported = false; - - // check if the msgtype is supported - if (TextUtils.equals(Event.EVENT_TYPE_MESSAGE, type)) { - try { - JsonObject eventContent = event.getContentAsJsonObject(); - String msgType = ""; - - JsonElement element = eventContent.get("msgtype"); - - if (null != element) { - msgType = element.getAsString(); - } - - isSupported = TextUtils.equals(msgType, Message.MSGTYPE_TEXT) - || TextUtils.equals(msgType, Message.MSGTYPE_EMOTE) - || TextUtils.equals(msgType, Message.MSGTYPE_NOTICE) - || TextUtils.equals(msgType, Message.MSGTYPE_IMAGE) - || TextUtils.equals(msgType, Message.MSGTYPE_AUDIO) - || TextUtils.equals(msgType, Message.MSGTYPE_VIDEO) - || TextUtils.equals(msgType, Message.MSGTYPE_FILE); - - if (!isSupported && !TextUtils.isEmpty(msgType)) { - Log.e(LOG_TAG, "isSupportedEvent : Unsupported msg type " + msgType); - } - } catch (Exception e) { - Log.e(LOG_TAG, "isSupportedEvent failed " + e.getMessage(), e); - } - } else if (TextUtils.equals(Event.EVENT_TYPE_MESSAGE_ENCRYPTED, type)) { - isSupported = event.hasContentFields(); - } else if (TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_MEMBER, type)) { - JsonObject eventContentAsJsonObject = event.getContentAsJsonObject(); - - if (null != eventContentAsJsonObject) { - if (eventContentAsJsonObject.entrySet().isEmpty()) { - Log.d(LOG_TAG, "isSupportedEvent : room member with no content is not supported"); - } else { - // do not display the avatar / display name update - EventContent prevEventContent = event.getPrevContent(); - EventContent eventContent = event.getEventContent(); - - String membership = null; - String preMembership = null; - - if (eventContent != null) { - membership = eventContent.membership; - } - - if (prevEventContent != null) { - preMembership = prevEventContent.membership; - } - - isSupported = !TextUtils.equals(membership, preMembership); - - if (!isSupported) { - Log.d(LOG_TAG, "isSupportedEvent : do not support avatar display name update"); - } - } - } - } else { - isSupported = sSupportedType.contains(type) - || (event.isCallEvent() && !TextUtils.isEmpty(type) && !Event.EVENT_TYPE_CALL_CANDIDATES.equals(type)); - } - - if (!isSupported) { - // some events are known to be never traced - // avoid warning when it is not required. - if (!sKnownUnsupportedType.contains(type)) { - Log.e(LOG_TAG, "isSupportedEvent : Unsupported event type " + type); - } - } - - return isSupported; - } - - /** - * @return the user id - */ - public String getUserId() { - return mUserId; - } - - /** - * @return the room id - */ - public String getRoomId() { - return mRoomId; - } - - /** - * @return the topic. - */ - public String getRoomTopic() { - return mTopic; - } - - /** - * @return the room summary event. - */ - public Event getLatestReceivedEvent() { - return mLatestReceivedEvent; - } - - /** - * @return the dedicated room state. - */ - public RoomState getLatestRoomState() { - return mLatestRoomState; - } - - /** - * @return true if the current user is invited - */ - public boolean isInvited() { - return RoomMember.MEMBERSHIP_INVITE.equals(mUserMembership); - } - - /** - * To call when the room is in the invited section of the sync response - */ - public void setIsInvited() { - mUserMembership = RoomMember.MEMBERSHIP_INVITE; - } - - /** - * To call when the room is in the joined section of the sync response - */ - public void setIsJoined() { - mUserMembership = RoomMember.MEMBERSHIP_JOIN; - } - - /** - * @return true if the current user is invited - */ - public boolean isJoined() { - return RoomMember.MEMBERSHIP_JOIN.equals(mUserMembership); - } - - /** - * @return the inviter user id. - */ - public String getInviterUserId() { - return mInviterUserId; - } - - /** - * Set the room's {@link org.matrix.androidsdk.rest.model.Event#EVENT_TYPE_STATE_ROOM_TOPIC}. - * - * @param topic The topic - * @return This summary for chaining calls. - */ - public RoomSummary setTopic(String topic) { - mTopic = topic; - return this; - } - - /** - * Set the room's ID.. - * - * @param roomId The room ID - * @return This summary for chaining calls. - */ - public RoomSummary setRoomId(String roomId) { - mRoomId = roomId; - return this; - } - - /** - * Set the latest tracked event (e.g. the latest m.room.message) - * - * @param event The most-recent event. - * @param roomState The room state - * @return This summary for chaining calls. - */ - public RoomSummary setLatestReceivedEvent(Event event, RoomState roomState) { - setLatestReceivedEvent(event); - setLatestRoomState(roomState); - - if (null != roomState) { - setTopic(roomState.topic); - } - return this; - } - - /** - * Set the latest tracked event (e.g. the latest m.room.message) - * - * @param event The most-recent event. - * @return This summary for chaining calls. - */ - public RoomSummary setLatestReceivedEvent(Event event) { - mLatestReceivedEvent = event; - return this; - } - - /** - * Set the latest RoomState - * - * @param roomState The room state of the latest event. - * @return This summary for chaining calls. - */ - public RoomSummary setLatestRoomState(RoomState roomState) { - mLatestRoomState = roomState; - - // Keep this code for compatibility? - boolean isInvited = false; - - // check for the invitation status - if (null != mLatestRoomState) { - RoomMember member = mLatestRoomState.getMember(mUserId); - isInvited = (null != member) && RoomMember.MEMBERSHIP_INVITE.equals(member.membership); - } - // when invited, the only received message should be the invitation one - if (isInvited) { - mInviterName = null; - - if (null != mLatestReceivedEvent) { - mInviterName = mInviterUserId = mLatestReceivedEvent.getSender(); - - // try to retrieve a display name - if (null != mLatestRoomState) { - mInviterName = mLatestRoomState.getMemberName(mLatestReceivedEvent.getSender()); - } - } - } else { - mInviterUserId = mInviterName = null; - } - - return this; - } - - /** - * Set the read receipt event Id - * - * @param eventId the read receipt event id. - */ - public void setReadReceiptEventId(String eventId) { - Log.d(LOG_TAG, "## setReadReceiptEventId() : " + eventId + " roomId " + getRoomId()); - mReadReceiptEventId = eventId; - } - - /** - * @return the read receipt event id - */ - public String getReadReceiptEventId() { - return mReadReceiptEventId; - } - - /** - * Set the read marker event Id - * - * @param eventId the read marker event id. - */ - public void setReadMarkerEventId(String eventId) { - Log.d(LOG_TAG, "## setReadMarkerEventId() : " + eventId + " roomId " + getRoomId()); - - if (TextUtils.isEmpty(eventId)) { - Log.e(LOG_TAG, "## setReadMarkerEventId') : null mReadMarkerEventId, in " + getRoomId()); - } - - mReadMarkerEventId = eventId; - } - - /** - * @return the read receipt event id - */ - public String getReadMarkerEventId() { - if (TextUtils.isEmpty(mReadMarkerEventId)) { - Log.e(LOG_TAG, "## getReadMarkerEventId') : null mReadMarkerEventId, in " + getRoomId()); - mReadMarkerEventId = getReadReceiptEventId(); - } - - return mReadMarkerEventId; - } - - /** - * Update the unread message counter - * - * @param count the unread events count. - */ - public void setUnreadEventsCount(int count) { - Log.d(LOG_TAG, "## setUnreadEventsCount() : " + count + " roomId " + getRoomId()); - mUnreadEventsCount = count; - } - - /** - * @return the unread events count - */ - public int getUnreadEventsCount() { - return mUnreadEventsCount; - } - - /** - * Update the notification counter - * - * @param count the notification counter - */ - public void setNotificationCount(int count) { - Log.d(LOG_TAG, "## setNotificationCount() : " + count + " roomId " + getRoomId()); - mNotificationCount = count; - } - - /** - * @return the notification count - */ - public int getNotificationCount() { - return mNotificationCount; - } - - /** - * Update the highlight counter - * - * @param count the highlight counter - */ - public void setHighlightCount(int count) { - Log.d(LOG_TAG, "## setHighlightCount() : " + count + " roomId " + getRoomId()); - mHighlightsCount = count; - } - - /** - * @return the highlight count - */ - public int getHighlightCount() { - return mHighlightsCount; - } - - /** - * @return the room tags - */ - public Set getRoomTags() { - return mRoomTags; - } - - /** - * Update the room tags - * - * @param roomTags the room tags - */ - public void setRoomTags(final Set roomTags) { - if (roomTags != null) { - // wraps the set into a serializable one - mRoomTags = new HashSet<>(roomTags); - } else { - mRoomTags = new HashSet<>(); - } - } - - public boolean isConferenceUserRoom() { - // test if it is not yet initialized - if (null == mIsConferenceUserRoom) { - - mIsConferenceUserRoom = false; - - // FIXME LazyLoading Heroes does not contains me - // FIXME I'ms not sure this code will work anymore - - Collection membersId = getHeroes(); - - // works only with 1:1 room - if (2 == membersId.size()) { - for (String userId : membersId) { - if (MXCallsManager.isConferenceUserId(userId)) { - mIsConferenceUserRoom = true; - break; - } - } - } - } - - return mIsConferenceUserRoom; - } - - public void setIsConferenceUserRoom(boolean isConferenceUserRoom) { - mIsConferenceUserRoom = isConferenceUserRoom; - } - - public void setRoomSyncSummary(@NonNull RoomSyncSummary roomSyncSummary) { - if (roomSyncSummary.heroes != null) { - mHeroes.clear(); - mHeroes.addAll(roomSyncSummary.heroes); - } - - if (roomSyncSummary.joinedMembersCount != null) { - // Update the value - mJoinedMembersCountFromSyncRoomSummary = roomSyncSummary.joinedMembersCount; - } - - if (roomSyncSummary.invitedMembersCount != null) { - // Update the value - mInvitedMembersCountFromSyncRoomSummary = roomSyncSummary.invitedMembersCount; - } - } - - @NonNull - public List getHeroes() { - return mHeroes; - } - - public int getNumberOfJoinedMembers() { - return mJoinedMembersCountFromSyncRoomSummary; - } - - public int getNumberOfInvitedMembers() { - return mInvitedMembersCountFromSyncRoomSummary; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomTag.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomTag.java deleted file mode 100644 index ec8d6f94..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/RoomTag.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2015 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.data; - -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.RoomTags; -import im.vector.matrix.android.internal.legacy.util.JsonUtils; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.util.HashMap; -import java.util.Map; - -/** - * Class representing a room tag. - */ -public class RoomTag implements java.io.Serializable { - private static final long serialVersionUID = 5172602958896551204L; - private static final String LOG_TAG = RoomTag.class.getSimpleName(); - - // - public static final String ROOM_TAG_FAVOURITE = "m.favourite"; - public static final String ROOM_TAG_LOW_PRIORITY = "m.lowpriority"; - public static final String ROOM_TAG_NO_TAG = "m.recent"; - public static final String ROOM_TAG_SERVER_NOTICE = "m.server_notice"; - - /** - * The name of a tag. - */ - public String mName; - - /** - * Try to parse order as Double. - * Provides nil if the items cannot be parsed. - */ - public Double mOrder; - - /** - * RoomTag creator. - * - * @param aName the tag name. - * @param anOrder the tag order - */ - public RoomTag(String aName, Double anOrder) { - mName = aName; - mOrder = anOrder; - } - - /** - * Extract a list of tags from a room tag event. - * - * @param event a room tag event (which can contains several tags) - * @return a dictionary containing the tags the user defined for one room. - */ - public static Map roomTagsWithTagEvent(Event event) { - Map tags = new HashMap<>(); - - try { - RoomTags roomtags = JsonUtils.toRoomTags(event.getContent()); - - if ((null != roomtags.tags) && (0 != roomtags.tags.size())) { - for (String tagName : roomtags.tags.keySet()) { - Map params = roomtags.tags.get(tagName); - if (params != null) { - tags.put(tagName, new RoomTag(tagName, params.get("order"))); - } else { - tags.put(tagName, new RoomTag(tagName, null)); - } - } - } - } catch (Exception e) { - Log.e(LOG_TAG, "roomTagsWithTagEvent fails " + e.getMessage(), e); - } - - return tags; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/comparator/Comparators.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/comparator/Comparators.java deleted file mode 100644 index 2c8c8749..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/comparator/Comparators.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.data.comparator; - -import im.vector.matrix.android.internal.legacy.interfaces.DatedObject; - -import java.util.Comparator; - -public class Comparators { - - // comparator to sort from the oldest to the latest. - public static final Comparator ascComparator = new Comparator() { - @Override - public int compare(DatedObject datedObject1, DatedObject datedObject2) { - return (int) (datedObject1.getDate() - datedObject2.getDate()); - } - }; - - // comparator to sort from the latest to the oldest. - public static final Comparator descComparator = new Comparator() { - @Override - public int compare(DatedObject datedObject1, DatedObject datedObject2) { - return (int) (datedObject2.getDate() - datedObject1.getDate()); - } - }; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/comparator/RoomComparatorWithTag.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/comparator/RoomComparatorWithTag.java deleted file mode 100644 index f42b600f..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/comparator/RoomComparatorWithTag.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.data.comparator; - -import im.vector.matrix.android.internal.legacy.data.Room; -import im.vector.matrix.android.internal.legacy.data.RoomTag; - -import java.util.Comparator; - -/** - * This class is responsible for comparing rooms by the tag's order - */ -public class RoomComparatorWithTag implements Comparator { - - private final String mTag; - - public RoomComparatorWithTag(final String tag) { - mTag = tag; - } - - @Override - public int compare(final Room r1, final Room r2) { - final int res; - final RoomTag tag1 = r1.getAccountData().roomTag(mTag); - final RoomTag tag2 = r2.getAccountData().roomTag(mTag); - - if (tag1 != null && tag1.mOrder != null && tag2 != null && tag2.mOrder != null) { - res = Double.compare(tag1.mOrder, tag2.mOrder); - } else if (tag1 != null && tag1.mOrder != null) { - res = 1; - } else { - res = -1; - } - return res; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/cryptostore/IMXCryptoStore.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/cryptostore/IMXCryptoStore.java deleted file mode 100644 index a4c4fb2d..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/cryptostore/IMXCryptoStore.java +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.data.cryptostore; - -import android.content.Context; - -import im.vector.matrix.android.api.auth.data.Credentials; -import im.vector.matrix.android.internal.legacy.crypto.IncomingRoomKeyRequest; -import im.vector.matrix.android.internal.legacy.crypto.OutgoingRoomKeyRequest; -import im.vector.matrix.android.internal.legacy.crypto.data.MXDeviceInfo; -import im.vector.matrix.android.internal.legacy.crypto.data.MXOlmInboundGroupSession2; -import org.matrix.olm.OlmAccount; -import org.matrix.olm.OlmSession; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * the crypto data store - */ -public interface IMXCryptoStore { - /** - * Init a crypto store for the passed getCredentials. - * - * @param context the application context - * @param credentials the getCredentials of the account. - */ - void initWithCredentials(Context context, Credentials credentials); - - /** - * @return if the corrupted is corrupted. - */ - boolean isCorrupted(); - - /** - * Indicate if the store contains data for the passed account. - * - * @return true means that the user enabled the crypto in a previous session - */ - boolean hasData(); - - /** - * Delete the crypto store for the passed getCredentials. - */ - void deleteStore(); - - /** - * open any existing crypto store - */ - void open(); - - /** - * Close the store - */ - void close(); - - /** - * Store the device id. - * - * @param deviceId the device id - */ - void storeDeviceId(String deviceId); - - /** - * @return the device id - */ - String getDeviceId(); - - /** - * Store the end to end account for the logged-in user. - * - * @param account the account to save - */ - void storeAccount(OlmAccount account); - - /** - * @return the olm account - */ - OlmAccount getAccount(); - - /** - * Store a device for a user. - * - * @param userId The user's id. - * @param device the device to store. - */ - void storeUserDevice(String userId, MXDeviceInfo device); - - /** - * Retrieve a device for a user. - * - * @param deviceId The device id. - * @param userId The user's id. - * @return A map from device id to 'MXDevice' object for the device. - */ - MXDeviceInfo getUserDevice(String deviceId, String userId); - - /** - * Store the known devices for a user. - * - * @param userId The user's id. - * @param devices A map from device id to 'MXDevice' object for the device. - */ - void storeUserDevices(String userId, Map devices); - - /** - * Retrieve the known devices for a user. - * - * @param userId The user's id. - * @return The devices map if some devices are known, else null - */ - Map getUserDevices(String userId); - - /** - * Store the crypto algorithm for a room. - * - * @param roomId the id of the room. - * @param algorithm the algorithm. - */ - void storeRoomAlgorithm(String roomId, String algorithm); - - /** - * Provides the algorithm used in a dedicated room. - * - * @param roomId the room id - * @return the algorithm, null is the room is not encrypted - */ - String getRoomAlgorithm(String roomId); - - /** - * Store a session between the logged-in user and another device. - * - * @param session the end-to-end session. - * @param deviceKey the public key of the other device. - */ - void storeSession(OlmSession session, String deviceKey); - - /** - * Retrieve the end-to-end sessions between the logged-in user and another - * device. - * - * @param deviceKey the public key of the other device. - * @return A map from sessionId to Base64 end-to-end session. - */ - Map getDeviceSessions(String deviceKey); - - /** - * Store an inbound group session. - * - * @param session the inbound group session and its context. - */ - void storeInboundGroupSession(MXOlmInboundGroupSession2 session); - - /** - * Retrieve an inbound group session. - * - * @param sessionId the session identifier. - * @param senderKey the base64-encoded curve25519 key of the sender. - * @return an inbound group session. - */ - MXOlmInboundGroupSession2 getInboundGroupSession(String sessionId, String senderKey); - - /** - * Retrieve the known inbound group sessions. - * - * @return an inbound group session. - */ - List getInboundGroupSessions(); - - /** - * Remove an inbound group session - * - * @param sessionId the session identifier. - * @param senderKey the base64-encoded curve25519 key of the sender. - */ - void removeInboundGroupSession(String sessionId, String senderKey); - - /** - * Set the global override for whether the client should ever send encrypted - * messages to unverified devices. - * If false, it can still be overridden per-room. - * If true, it overrides the per-room settings. - * - * @param block true to unilaterally blacklist all - */ - void setGlobalBlacklistUnverifiedDevices(boolean block); - - /** - * @return true to unilaterally blacklist all unverified devices. - */ - boolean getGlobalBlacklistUnverifiedDevices(); - - /** - * Updates the rooms ids list in which the messages are not encrypted for the unverified devices. - * - * @param roomIds the room ids list - */ - void setRoomsListBlacklistUnverifiedDevices(List roomIds); - - /** - * Provides the rooms ids list in which the messages are not encrypted for the unverified devices. - * - * @return the room Ids list - */ - List getRoomsListBlacklistUnverifiedDevices(); - - /** - * @return the devices statuses map - */ - Map getDeviceTrackingStatuses(); - - /** - * Save the device statuses - * - * @param deviceTrackingStatuses the device tracking statuses - */ - void saveDeviceTrackingStatuses(Map deviceTrackingStatuses); - - /** - * Get the tracking status of a specified userId devices. - * - * @param userId the user id - * @param defaultValue the default avlue - * @return the tracking status - */ - int getDeviceTrackingStatus(String userId, int defaultValue); - - /** - * Look for an existing outgoing room key request, and if none is found, - * - * @param requestBody the request body - * @return an OutgoingRoomKeyRequest instance or null - */ - OutgoingRoomKeyRequest getOutgoingRoomKeyRequest(Map requestBody); - - /** - * Look for an existing outgoing room key request, and if none is found, - * + add a new one. - * - * @param request the request - * @return either the same instance as passed in, or the existing one. - */ - OutgoingRoomKeyRequest getOrAddOutgoingRoomKeyRequest(OutgoingRoomKeyRequest request); - - /** - * Look for room key requests by state. - * - * @param states the states - * @return an OutgoingRoomKeyRequest or null - */ - OutgoingRoomKeyRequest getOutgoingRoomKeyRequestByState(Set states); - - /** - * Update an existing outgoing request. - * - * @param request the request - */ - void updateOutgoingRoomKeyRequest(OutgoingRoomKeyRequest request); - - /** - * Delete an outgoing room key request. - * - * @param transactionId the transaction id. - */ - void deleteOutgoingRoomKeyRequest(String transactionId); - - /** - * Store an incomingRoomKeyRequest instance - * - * @param incomingRoomKeyRequest the incoming key request - */ - void storeIncomingRoomKeyRequest(IncomingRoomKeyRequest incomingRoomKeyRequest); - - /** - * Delete an incomingRoomKeyRequest instance - * - * @param incomingRoomKeyRequest the incoming key request - */ - void deleteIncomingRoomKeyRequest(IncomingRoomKeyRequest incomingRoomKeyRequest); - - /** - * Search an IncomingRoomKeyRequest - * - * @param userId the user id - * @param deviceId the device id - * @param requestId the request id - * @return an IncomingRoomKeyRequest if it exists, else null - */ - IncomingRoomKeyRequest getIncomingRoomKeyRequest(String userId, String deviceId, String requestId); - - /** - * @return the pending IncomingRoomKeyRequest requests - */ - List getPendingIncomingRoomKeyRequests(); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/cryptostore/MXFileCryptoStore.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/cryptostore/MXFileCryptoStore.java deleted file mode 100644 index e8eff7d9..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/cryptostore/MXFileCryptoStore.java +++ /dev/null @@ -1,1743 +0,0 @@ -/* - * Copyright 2015 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.data.cryptostore; - -import android.content.Context; -import android.os.Looper; -import android.text.TextUtils; - -import org.matrix.olm.OlmAccount; -import org.matrix.olm.OlmSession; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.zip.GZIPInputStream; -import java.util.zip.GZIPOutputStream; - -import im.vector.matrix.android.api.auth.data.Credentials; -import im.vector.matrix.android.internal.legacy.crypto.IncomingRoomKeyRequest; -import im.vector.matrix.android.internal.legacy.crypto.OutgoingRoomKeyRequest; -import im.vector.matrix.android.internal.legacy.crypto.data.MXDeviceInfo; -import im.vector.matrix.android.internal.legacy.crypto.data.MXOlmInboundGroupSession; -import im.vector.matrix.android.internal.legacy.crypto.data.MXOlmInboundGroupSession2; -import im.vector.matrix.android.internal.legacy.crypto.data.MXUsersDevicesMap; -import im.vector.matrix.android.internal.legacy.util.CompatUtil; -import im.vector.matrix.android.internal.legacy.util.ContentUtils; -import im.vector.matrix.android.internal.legacy.util.Log; - -/** - * the crypto data store - */ -public class MXFileCryptoStore implements IMXCryptoStore { - private static final String LOG_TAG = MXFileCryptoStore.class.getSimpleName(); - - private static final int MXFILE_CRYPTO_VERSION = 1; - - private static final String MXFILE_CRYPTO_STORE_FOLDER = "MXFileCryptoStore"; - - private static final String MXFILE_CRYPTO_STORE_METADATA_FILE = "MXFileCryptoStore"; - private static final String MXFILE_CRYPTO_STORE_METADATA_FILE_TMP = "MXFileCryptoStore.tmp"; - - private static final String MXFILE_CRYPTO_STORE_ACCOUNT_FILE = "account"; - private static final String MXFILE_CRYPTO_STORE_ACCOUNT_FILE_TMP = "account.tmp"; - - private static final String MXFILE_CRYPTO_STORE_DEVICES_FOLDER = "devicesFolder"; - private static final String MXFILE_CRYPTO_STORE_DEVICES_FILE = "devices"; - private static final String MXFILE_CRYPTO_STORE_DEVICES_FILE_TMP = "devices.tmp"; - - private static final String MXFILE_CRYPTO_STORE_TRACKING_STATUSES_FILE = "trackingStatuses"; - private static final String MXFILE_CRYPTO_STORE_TRACKING_STATUSES_FILE_TMP = "trackingStatuses.tmp"; - - private static final String MXFILE_CRYPTO_STORE_ALGORITHMS_FILE = "roomsAlgorithms"; - private static final String MXFILE_CRYPTO_STORE_ALGORITHMS_FILE_TMP = "roomsAlgorithms.tmp"; - - private static final String MXFILE_CRYPTO_STORE_OLM_SESSIONS_FILE = "sessions"; - private static final String MXFILE_CRYPTO_STORE_OLM_SESSIONS_FILE_TMP = "sessions.tmp"; - private static final String MXFILE_CRYPTO_STORE_OLM_SESSIONS_FOLDER = "olmSessionsFolder"; - - private static final String MXFILE_CRYPTO_STORE_INBOUND_GROUP_SESSIONS_FILE = "inboundGroupSessions"; - private static final String MXFILE_CRYPTO_STORE_INBOUND_GROUP_SESSIONS_FILE_TMP = "inboundGroupSessions.tmp"; - private static final String MXFILE_CRYPTO_STORE_INBOUND_GROUP_SESSIONS_FOLDER = "inboundGroupSessionsFolder"; - - private static final String MXFILE_CRYPTO_STORE_OUTGOING_ROOM_KEY_REQUEST_FILE = "outgoingRoomKeyRequests"; - private static final String MXFILE_CRYPTO_STORE_OUTGOING_ROOM_KEY_REQUEST_FILE_TMP = "outgoingRoomKeyRequests.tmp"; - - private static final String MXFILE_CRYPTO_STORE_INCOMING_ROOM_KEY_REQUESTS_FILE = "incomingRoomKeyRequests"; - private static final String MXFILE_CRYPTO_STORE_INCOMING_ROOM_KEY_REQUESTS_FILE_TMP = "incomingRoomKeyRequests.tmp"; - - // The getCredentials used for this store - private Credentials mCredentials; - - // Meta data about the store - private MXFileCryptoStoreMetaData2 mMetaData; - - // The olm account - private OlmAccount mOlmAccount; - - // All users devices keys - private MXUsersDevicesMap mUsersDevicesInfoMap; - private final Object mUsersDevicesInfoMapLock = new Object(); - - // The algorithms used in rooms - private Map mRoomsAlgorithms; - - // the tracking statuses - private Map mTrackingStatuses; - - // The olm sessions ( -> ( -> ) - private Map> mOlmSessions; - private static final Object mOlmSessionsLock = new Object(); - - // The inbound group megolm sessions ( -> ( -> ) - private Map> mInboundGroupSessions; - private final Object mInboundGroupSessionsLock = new Object(); - - private final Map, OutgoingRoomKeyRequest> mOutgoingRoomKeyRequests = new HashMap<>(); - - // userId -> deviceId -> [keyRequest] - private Map>> mPendingIncomingRoomKeyRequests; - - // The path of the MXFileCryptoStore folder - private File mStoreFile; - - private File mMetaDataFile; - private File mMetaDataFileTmp; - - private File mAccountFile; - private File mAccountFileTmp; - - private File mDevicesFolder; - private File mDevicesFile; - private File mDevicesFileTmp; - - private File mAlgorithmsFile; - private File mAlgorithmsFileTmp; - - private File mTrackingStatusesFile; - private File mTrackingStatusesFileTmp; - - private File mOlmSessionsFile; - private File mOlmSessionsFileTmp; - private File mOlmSessionsFolder; - - private File mInboundGroupSessionsFile; - private File mInboundGroupSessionsFileTmp; - private File mInboundGroupSessionsFolder; - - private File mOutgoingRoomKeyRequestsFile; - private File mOutgoingRoomKeyRequestsFileTmp; - - private File mIncomingRoomKeyRequestsFile; - private File mIncomingRoomKeyRequestsFileTmp; - - // tell if the store is corrupted - private boolean mIsCorrupted = false; - - // tell if the store is ready - private boolean mIsReady = false; - - private Context mContext; - - // True if file encryption is enabled - private final boolean mEnableFileEncryption; - - /** - * Constructor - * - * @param enableFileEncryption set to true to enable file encryption. - */ - public MXFileCryptoStore(boolean enableFileEncryption) { - mEnableFileEncryption = enableFileEncryption; - } - - @Override - public void initWithCredentials(Context context, Credentials credentials) { - mCredentials = credentials; - - mStoreFile = new File(new File(context.getApplicationContext().getFilesDir(), MXFILE_CRYPTO_STORE_FOLDER), mCredentials.getUserId()); - - mMetaDataFile = new File(mStoreFile, MXFILE_CRYPTO_STORE_METADATA_FILE); - mMetaDataFileTmp = new File(mStoreFile, MXFILE_CRYPTO_STORE_METADATA_FILE_TMP); - - mAccountFile = new File(mStoreFile, MXFILE_CRYPTO_STORE_ACCOUNT_FILE); - mAccountFileTmp = new File(mStoreFile, MXFILE_CRYPTO_STORE_ACCOUNT_FILE_TMP); - - mDevicesFolder = new File(mStoreFile, MXFILE_CRYPTO_STORE_DEVICES_FOLDER); - mDevicesFile = new File(mStoreFile, MXFILE_CRYPTO_STORE_DEVICES_FILE); - mDevicesFileTmp = new File(mStoreFile, MXFILE_CRYPTO_STORE_DEVICES_FILE_TMP); - - mAlgorithmsFile = new File(mStoreFile, MXFILE_CRYPTO_STORE_ALGORITHMS_FILE); - mAlgorithmsFileTmp = new File(mStoreFile, MXFILE_CRYPTO_STORE_ALGORITHMS_FILE_TMP); - - mTrackingStatusesFile = new File(mStoreFile, MXFILE_CRYPTO_STORE_TRACKING_STATUSES_FILE); - mTrackingStatusesFileTmp = new File(mStoreFile, MXFILE_CRYPTO_STORE_TRACKING_STATUSES_FILE_TMP); - - // backward compatibility : the sessions used to be stored in an unique file - mOlmSessionsFile = new File(mStoreFile, MXFILE_CRYPTO_STORE_OLM_SESSIONS_FILE); - mOlmSessionsFileTmp = new File(mStoreFile, MXFILE_CRYPTO_STORE_OLM_SESSIONS_FILE_TMP); - // each session is now stored in a dedicated file - mOlmSessionsFolder = new File(mStoreFile, MXFILE_CRYPTO_STORE_OLM_SESSIONS_FOLDER); - - mInboundGroupSessionsFile = new File(mStoreFile, MXFILE_CRYPTO_STORE_INBOUND_GROUP_SESSIONS_FILE); - mInboundGroupSessionsFileTmp = new File(mStoreFile, MXFILE_CRYPTO_STORE_INBOUND_GROUP_SESSIONS_FILE_TMP); - mInboundGroupSessionsFolder = new File(mStoreFile, MXFILE_CRYPTO_STORE_INBOUND_GROUP_SESSIONS_FOLDER); - - mOutgoingRoomKeyRequestsFile = new File(mStoreFile, MXFILE_CRYPTO_STORE_OUTGOING_ROOM_KEY_REQUEST_FILE); - mOutgoingRoomKeyRequestsFileTmp = new File(mStoreFile, MXFILE_CRYPTO_STORE_OUTGOING_ROOM_KEY_REQUEST_FILE_TMP); - - mIncomingRoomKeyRequestsFile = new File(mStoreFile, MXFILE_CRYPTO_STORE_INCOMING_ROOM_KEY_REQUESTS_FILE); - mIncomingRoomKeyRequestsFileTmp = new File(mStoreFile, MXFILE_CRYPTO_STORE_INCOMING_ROOM_KEY_REQUESTS_FILE_TMP); - - // Build default metadata - if (mMetaData == null) { - mMetaData = new MXFileCryptoStoreMetaData2(mCredentials.getUserId(), mCredentials.getDeviceId(), MXFILE_CRYPTO_VERSION); - } - - mUsersDevicesInfoMap = new MXUsersDevicesMap<>(); - mRoomsAlgorithms = new HashMap<>(); - mTrackingStatuses = new HashMap<>(); - mOlmSessions = new HashMap<>(); - mInboundGroupSessions = new HashMap<>(); - - mContext = context; - } - - @Override - public boolean hasData() { - boolean result = mStoreFile.exists(); - - if (result) { - // User ids match. Check device ids - loadMetaData(); - - if (null != mMetaData) { - result = TextUtils.isEmpty(mMetaData.mDeviceId) - || TextUtils.equals(mCredentials.getDeviceId(), mMetaData.mDeviceId); - } - } - - return result; - } - - - @Override - public boolean isCorrupted() { - return mIsCorrupted; - } - - @Override - public void deleteStore() { - // delete the dedicated directories - try { - ContentUtils.deleteDirectory(mStoreFile); - } catch (Exception e) { - Log.e(LOG_TAG, "deleteStore failed " + e.getMessage(), e); - } - } - - @Override - public void open() { - if (mIsReady) { - Log.e(LOG_TAG, "## open() : the store is already opened"); - } else { - mMetaData = null; - - loadMetaData(); - - // Check if - if (null == mMetaData) { - resetData(); - } - // Check store version - else if (MXFILE_CRYPTO_VERSION != mMetaData.mVersion) { - Log.e(LOG_TAG, "## open() : New MXFileCryptoStore version detected"); - resetData(); - } - // Check getCredentials - // The device id may not have been provided in getCredentials. - // Check it only if provided, else trust the stored one. - else if (!TextUtils.equals(mMetaData.mUserId, mCredentials.getUserId()) - || ((null != mCredentials.getDeviceId()) && !TextUtils.equals(mCredentials.getDeviceId(), mMetaData.mDeviceId))) { - Log.e(LOG_TAG, "## open() : Credentials do not match"); - resetData(); - } - - // If metaData is still defined, we can load rooms data - if (null != mMetaData) { - preloadCryptoData(); - } - - // Else, if getCredentials is valid, create and store it - if (mMetaData == null){ - mMetaData = new MXFileCryptoStoreMetaData2(mCredentials.getUserId(), mCredentials.getDeviceId(), MXFILE_CRYPTO_VERSION); - mIsReady = true; - // flush the metadata - saveMetaData(); - } else { - mIsReady = true; - } - } - } - - @Override - public void storeDeviceId(String deviceId) { - if (!mIsReady) { - Log.e(LOG_TAG, "## storeDeviceId() : the store is not ready"); - return; - } - - mMetaData.mDeviceId = deviceId; - saveMetaData(); - } - - @Override - public String getDeviceId() { - if (!mIsReady) { - Log.e(LOG_TAG, "## getDeviceId() : the store is not ready"); - return null; - } - - return mMetaData.mDeviceId; - } - - /** - * Store a serializable object into a dedicated file. - * - * @param object the object to write. - * @param folder the folder - * @param filename the filename - * @param description the object description - * @return true if the operation succeeds - */ - private boolean storeObject(Object object, File folder, String filename, String description) { - if (!mIsReady) { - Log.e(LOG_TAG, "## storeObject() : the store is not ready"); - return false; - } - - // sanity checks - if ((null == object) || (null == folder) || (null == filename)) { - Log.e(LOG_TAG, "## storeObject() : invalid parameters"); - return false; - } - - // ensure that the folder exists - // it should always exist but it happened - if (!folder.exists()) { - if (!folder.mkdirs()) { - Log.e(LOG_TAG, "Cannot create the folder " + folder); - } - } - - return storeObject(object, new File(folder, filename), description); - } - - /** - * Store a serializable object into a dedicated file. - * - * @param object the object to write. - * @param file the file - * @param description the object description - * @return true if the operation succeeds - */ - private boolean storeObject(Object object, File file, String description) { - if (!mIsReady) { - Log.e(LOG_TAG, "## storeObject() : the store is not ready"); - return false; - } - - if (Thread.currentThread() == Looper.getMainLooper().getThread()) { - Log.e(LOG_TAG, "## storeObject() : should not be called in the UI thread " + description); - } - - boolean succeed = false; - - synchronized (LOG_TAG) { - try { - long t0 = System.currentTimeMillis(); - - if (file.exists()) { - file.delete(); - } - - FileOutputStream fos = new FileOutputStream(file); - OutputStream cos; - if (mEnableFileEncryption) { - cos = CompatUtil.createCipherOutputStream(fos, mContext); - } else { - cos = fos; - } - GZIPOutputStream gz = CompatUtil.createGzipOutputStream(cos); - ObjectOutputStream out = new ObjectOutputStream(gz); - - out.writeObject(object); - out.flush(); - out.close(); - - succeed = true; - Log.d(LOG_TAG, "## storeObject () : " + description + " done in " + (System.currentTimeMillis() - t0) + " ms"); - - } catch (OutOfMemoryError oom) { - Log.e(LOG_TAG, "storeObject failed : " + description + " -- " + oom.getMessage(), oom); - } catch (Exception e) { - Log.e(LOG_TAG, "storeObject failed : " + description + " -- " + e.getMessage(), e); - } - } - - return succeed; - } - - /** - * Save the metadata into the crypto file store - */ - private void saveMetaData() { - if (mMetaDataFileTmp.exists()) { - mMetaDataFileTmp.delete(); - } - - if (mMetaDataFile.exists()) { - mMetaDataFile.renameTo(mMetaDataFileTmp); - } - - if (storeObject(mMetaData, mMetaDataFile, "saveMetaData")) { - if (mMetaDataFileTmp.exists()) { - mMetaDataFileTmp.delete(); - } - } else { - if (mMetaDataFileTmp.exists()) { - mMetaDataFileTmp.renameTo(mMetaDataFile); - } - } - } - - @Override - public void storeAccount(OlmAccount account) { - if (!mIsReady) { - Log.e(LOG_TAG, "## storeAccount() : the store is not ready"); - return; - } - - mOlmAccount = account; - - if (mAccountFileTmp.exists()) { - mAccountFileTmp.delete(); - } - - if (mAccountFile.exists()) { - mAccountFile.renameTo(mAccountFileTmp); - } - - if (storeObject(mOlmAccount, mAccountFile, "storeAccount")) { - if (mAccountFileTmp.exists()) { - mAccountFileTmp.delete(); - } - } else { - if (mAccountFileTmp.exists()) { - mAccountFileTmp.renameTo(mAccountFile); - } - } - } - - @Override - public OlmAccount getAccount() { - if (!mIsReady) { - Log.e(LOG_TAG, "## getAccount() : the store is not ready"); - return null; - } - - return mOlmAccount; - } - - /** - * Load the user devices from the filesystem - * if it is not yet done. - * - * @param userId the user id. - */ - private void loadUserDevices(String userId) { - if (!TextUtils.isEmpty(userId)) { - boolean alreadyDone; - - synchronized (mUsersDevicesInfoMapLock) { - alreadyDone = mUsersDevicesInfoMap.getMap().containsKey(userId); - } - - if (!alreadyDone) { - File devicesFile = new File(mDevicesFolder, userId); - - if (devicesFile.exists()) { - long t0 = System.currentTimeMillis(); - - // clear the corrupted flag - mIsCorrupted = false; - - Object devicesMapAsVoid = loadObject(devicesFile, "load devices of " + userId); - - if (null != devicesMapAsVoid) { - try { - synchronized (mUsersDevicesInfoMapLock) { - mUsersDevicesInfoMap.setObjects((Map) devicesMapAsVoid, userId); - } - } catch (Exception e) { - Log.e(LOG_TAG, "## loadUserDevices : mUsersDevicesInfoMap.setObjects failed " + e.getMessage(), e); - mIsCorrupted = true; - } - } - - // something was wrong (loadObject set this boolean) - if (mIsCorrupted) { - Log.e(LOG_TAG, "## loadUserDevices : failed to load the device of " + userId); - - // delete the corrupted file - devicesFile.delete(); - // it is not a blocking thing - mIsCorrupted = false; - } else { - Log.d(LOG_TAG, "## loadUserDevices : Load the devices of " + userId + " in " + (System.currentTimeMillis() - t0) + "ms"); - } - } - } - } - } - - @Override - public void storeUserDevice(String userId, MXDeviceInfo device) { - if (!mIsReady) { - Log.e(LOG_TAG, "## storeUserDevice() : the store is not ready"); - return; - } - - final Map devicesMap; - - loadUserDevices(userId); - - synchronized (mUsersDevicesInfoMapLock) { - mUsersDevicesInfoMap.setObject(device, userId, device.deviceId); - devicesMap = new HashMap<>(mUsersDevicesInfoMap.getMap().get(userId)); - } - - storeObject(devicesMap, mDevicesFolder, userId, "storeUserDevice " + userId + " with " + devicesMap.size() + " devices"); - } - - @Override - public MXDeviceInfo getUserDevice(String deviceId, String userId) { - if (!mIsReady) { - Log.e(LOG_TAG, "## getUserDevice() : the store is not ready"); - return null; - } - - MXDeviceInfo deviceInfo; - - loadUserDevices(userId); - - synchronized (mUsersDevicesInfoMapLock) { - deviceInfo = mUsersDevicesInfoMap.getObject(deviceId, userId); - } - - return deviceInfo; - } - - @Override - public void storeUserDevices(String userId, Map devices) { - if (!mIsReady) { - Log.e(LOG_TAG, "## storeUserDevices() : the store is not ready"); - return; - } - - synchronized (mUsersDevicesInfoMapLock) { - mUsersDevicesInfoMap.setObjects(devices, userId); - } - - storeObject(devices, mDevicesFolder, userId, "storeUserDevice " + userId); - } - - @Override - public Map getUserDevices(String userId) { - if (!mIsReady) { - Log.e(LOG_TAG, "## getUserDevices() : the store is not ready"); - return null; - } - - if (null != userId) { - Map devicesMap; - - loadUserDevices(userId); - - synchronized (mUsersDevicesInfoMapLock) { - devicesMap = mUsersDevicesInfoMap.getMap().get(userId); - } - - return devicesMap; - } else { - return null; - } - } - - @Override - public void storeRoomAlgorithm(String roomId, String algorithm) { - if (!mIsReady) { - Log.e(LOG_TAG, "## storeRoomAlgorithm() : the store is not ready"); - return; - } - - if ((null != roomId) && (null != algorithm)) { - mRoomsAlgorithms.put(roomId, algorithm); - - // delete the previous tmp - if (mAlgorithmsFileTmp.exists()) { - mAlgorithmsFileTmp.delete(); - } - - // copy the existing file - if (mAlgorithmsFile.exists()) { - mAlgorithmsFile.renameTo(mAlgorithmsFileTmp); - } - - if (storeObject(mRoomsAlgorithms, mAlgorithmsFile, "storeAlgorithmForRoom - in background")) { - // remove the tmp file - if (mAlgorithmsFileTmp.exists()) { - mAlgorithmsFileTmp.delete(); - } - } else { - if (mAlgorithmsFileTmp.exists()) { - mAlgorithmsFileTmp.renameTo(mAlgorithmsFile); - } - } - } - } - - @Override - public String getRoomAlgorithm(String roomId) { - if (!mIsReady) { - Log.e(LOG_TAG, "## getRoomAlgorithm() : the store is not ready"); - return null; - } - - if (null != roomId) { - return mRoomsAlgorithms.get(roomId); - } - - return null; - } - - @Override - public int getDeviceTrackingStatus(String userId, int defaultValue) { - if (!mIsReady) { - Log.e(LOG_TAG, "## getDeviceTrackingStatus() : the store is not ready"); - return defaultValue; - } - - if ((null != userId) && mTrackingStatuses.containsKey(userId)) { - return mTrackingStatuses.get(userId); - } else { - return defaultValue; - } - } - - @Override - public Map getDeviceTrackingStatuses() { - if (!mIsReady) { - Log.e(LOG_TAG, "## getDeviceTrackingStatuses() : the store is not ready"); - return null; - } - - return new HashMap<>(mTrackingStatuses); - } - - /** - * Save the tracking statuses map - */ - private void saveDeviceTrackingStatuses() { - // delete the previous tmp - if (mTrackingStatusesFileTmp.exists()) { - mTrackingStatusesFileTmp.delete(); - } - - // copy the existing file - if (mTrackingStatusesFile.exists()) { - mTrackingStatusesFile.renameTo(mTrackingStatusesFileTmp); - } - - if (storeObject(mTrackingStatuses, mTrackingStatusesFile, "saveDeviceTrackingStatus - in background")) { - // remove the tmp file - if (mTrackingStatusesFileTmp.exists()) { - mTrackingStatusesFileTmp.delete(); - } - } else { - if (mTrackingStatusesFileTmp.exists()) { - mTrackingStatusesFileTmp.renameTo(mTrackingStatusesFile); - } - } - } - - @Override - public void saveDeviceTrackingStatuses(Map deviceTrackingStatuses) { - if (!mIsReady) { - Log.e(LOG_TAG, "## saveDeviceTrackingStatuses() : the store is not ready"); - return; - } - - mTrackingStatuses.clear(); - mTrackingStatuses.putAll(deviceTrackingStatuses); - saveDeviceTrackingStatuses(); - } - - @Override - public void storeSession(final OlmSession olmSession, final String deviceKey) { - if (!mIsReady) { - Log.e(LOG_TAG, "## storeSession() : the store is not ready"); - return; - } - - String sessionIdentifier = null; - - if (null != olmSession) { - try { - sessionIdentifier = olmSession.sessionIdentifier(); - } catch (Exception e) { - Log.e(LOG_TAG, "## storeSession : session.sessionIdentifier() failed " + e.getMessage(), e); - } - } - - if ((null != deviceKey) && (null != sessionIdentifier)) { - synchronized (mOlmSessionsLock) { - if (!mOlmSessions.containsKey(deviceKey)) { - mOlmSessions.put(deviceKey, new HashMap()); - } - - OlmSession prevOlmSession = mOlmSessions.get(deviceKey).get(sessionIdentifier); - - // test if the session is a new one - if (olmSession != prevOlmSession) { - if (null != prevOlmSession) { - prevOlmSession.releaseSession(); - } - mOlmSessions.get(deviceKey).put(sessionIdentifier, olmSession); - } - } - - final File keyFolder = new File(mOlmSessionsFolder, encodeFilename(deviceKey)); - - if (!keyFolder.exists()) { - keyFolder.mkdir(); - } - - storeObject(olmSession, keyFolder, encodeFilename(sessionIdentifier), "Store olm session " + deviceKey + " " + sessionIdentifier); - } - } - - @Override - public Map getDeviceSessions(String deviceKey) { - if (!mIsReady) { - Log.e(LOG_TAG, "## storeSession() : the store is not ready"); - return null; - } - - if (null != deviceKey) { - Map map; - - synchronized (mOlmSessionsLock) { - map = mOlmSessions.get(deviceKey); - } - - return map; - } - - return null; - } - - @Override - public void removeInboundGroupSession(String sessionId, String senderKey) { - if (!mIsReady) { - Log.e(LOG_TAG, "## removeInboundGroupSession() : the store is not ready"); - return; - } - - if ((null != sessionId) && (null != senderKey)) { - synchronized (mInboundGroupSessionsLock) { - if (mInboundGroupSessions.containsKey(senderKey)) { - MXOlmInboundGroupSession2 session = mInboundGroupSessions.get(senderKey).get(sessionId); - - if (null != session) { - mInboundGroupSessions.get(senderKey).remove(sessionId); - - File senderKeyFolder = new File(mInboundGroupSessionsFolder, encodeFilename(session.mSenderKey)); - - if (senderKeyFolder.exists()) { - File inboundSessionFile = new File(senderKeyFolder, encodeFilename(sessionId)); - - if (!inboundSessionFile.delete()) { - Log.e(LOG_TAG, "## removeInboundGroupSession() : fail to remove the sessionid " + sessionId); - } - } - - // release the memory - session.mSession.releaseSession(); - } - } - } - } - } - - @Override - public void storeInboundGroupSession(final MXOlmInboundGroupSession2 session) { - if (!mIsReady) { - Log.e(LOG_TAG, "## storeInboundGroupSession() : the store is not ready"); - return; - } - - String sessionIdentifier = null; - - if ((null != session) && (null != session.mSenderKey) && (null != session.mSession)) { - try { - sessionIdentifier = session.mSession.sessionIdentifier(); - } catch (Exception e) { - Log.e(LOG_TAG, "## storeInboundGroupSession() : sessionIdentifier failed " + e.getMessage(), e); - } - } - - if (null != sessionIdentifier) { - synchronized (mInboundGroupSessionsLock) { - if (!mInboundGroupSessions.containsKey(session.mSenderKey)) { - mInboundGroupSessions.put(session.mSenderKey, new HashMap()); - } - - MXOlmInboundGroupSession2 curSession = mInboundGroupSessions.get(session.mSenderKey).get(sessionIdentifier); - - if (curSession != session) { - // release memory - if (null != curSession) { - curSession.mSession.releaseSession(); - } - // update the map - mInboundGroupSessions.get(session.mSenderKey).put(sessionIdentifier, session); - } - } - - Log.d(LOG_TAG, "## storeInboundGroupSession() : store session " + sessionIdentifier); - - File senderKeyFolder = new File(mInboundGroupSessionsFolder, encodeFilename(session.mSenderKey)); - - if (!senderKeyFolder.exists()) { - senderKeyFolder.mkdir(); - } - - storeObject(session, senderKeyFolder, encodeFilename(sessionIdentifier), "storeInboundGroupSession - in background"); - } - } - - @Override - public MXOlmInboundGroupSession2 getInboundGroupSession(String sessionId, String senderKey) { - if (!mIsReady) { - Log.e(LOG_TAG, "## getInboundGroupSession() : the store is not ready"); - return null; - } - - if ((null != sessionId) && (null != senderKey) && mInboundGroupSessions.containsKey(senderKey)) { - MXOlmInboundGroupSession2 session = null; - - try { - synchronized (mInboundGroupSessionsLock) { - session = mInboundGroupSessions.get(senderKey).get(sessionId); - } - } catch (Exception e) { - // it should never happen - // MXOlmInboundGroupSession has been replaced by MXOlmInboundGroupSession2 - // but it seems that the application code is not properly updated (JIT issue) ? - Log.e(LOG_TAG, "## getInboundGroupSession() failed " + e.getMessage(), e); - } - - return session; - } - return null; - } - - @Override - public List getInboundGroupSessions() { - if (!mIsReady) { - Log.e(LOG_TAG, "## getInboundGroupSessions() : the store is not ready"); - return null; - } - - List inboundGroupSessions = new ArrayList<>(); - - synchronized (mInboundGroupSessionsLock) { - for (String senderKey : mInboundGroupSessions.keySet()) { - inboundGroupSessions.addAll(mInboundGroupSessions.get(senderKey).values()); - } - } - - return inboundGroupSessions; - } - - @Override - public void close() { - // release JNI objects - List olmSessions = new ArrayList<>(); - Collection> sessionValues = mOlmSessions.values(); - - for (Map value : sessionValues) { - olmSessions.addAll(value.values()); - } - - for (OlmSession olmSession : olmSessions) { - olmSession.releaseSession(); - } - mOlmSessions.clear(); - - List groupSessions = new ArrayList<>(); - Collection> groupSessionsValues = mInboundGroupSessions.values(); - - for (Map map : groupSessionsValues) { - groupSessions.addAll(map.values()); - } - - for (MXOlmInboundGroupSession2 groupSession : groupSessions) { - if (null != groupSession.mSession) { - groupSession.mSession.releaseSession(); - } - } - mInboundGroupSessions.clear(); - } - - @Override - public void setGlobalBlacklistUnverifiedDevices(boolean block) { - if (!mIsReady) { - Log.e(LOG_TAG, "## setGlobalBlacklistUnverifiedDevices() : the store is not ready"); - return; - } - - mMetaData.mGlobalBlacklistUnverifiedDevices = block; - saveMetaData(); - } - - @Override - public boolean getGlobalBlacklistUnverifiedDevices() { - if (!mIsReady) { - Log.e(LOG_TAG, "## getGlobalBlacklistUnverifiedDevices() : the store is not ready"); - return false; - } - - return mMetaData.mGlobalBlacklistUnverifiedDevices; - } - - @Override - public void setRoomsListBlacklistUnverifiedDevices(List roomIds) { - if (!mIsReady) { - Log.e(LOG_TAG, "## setRoomsListBlacklistUnverifiedDevices() : the store is not ready"); - return; - } - - mMetaData.mBlacklistUnverifiedDevicesRoomIdsList = roomIds; - saveMetaData(); - } - - @Override - public List getRoomsListBlacklistUnverifiedDevices() { - if (!mIsReady) { - Log.e(LOG_TAG, "## getRoomsListBlacklistUnverifiedDevices() : the store is not ready"); - return null; - } - - if (null == mMetaData.mBlacklistUnverifiedDevicesRoomIdsList) { - return new ArrayList<>(); - } else { - return new ArrayList<>(mMetaData.mBlacklistUnverifiedDevicesRoomIdsList); - } - } - - /** - * save the outgoing room key requests. - */ - private void saveOutgoingRoomKeyRequests() { - if (mOutgoingRoomKeyRequestsFileTmp.exists()) { - mOutgoingRoomKeyRequestsFileTmp.delete(); - } - - if (mOutgoingRoomKeyRequestsFile.exists()) { - mOutgoingRoomKeyRequestsFile.renameTo(mOutgoingRoomKeyRequestsFileTmp); - } - - if (storeObject(mOutgoingRoomKeyRequests, mOutgoingRoomKeyRequestsFile, "saveOutgoingRoomKeyRequests")) { - if (mOutgoingRoomKeyRequestsFileTmp.exists()) { - mOutgoingRoomKeyRequestsFileTmp.delete(); - } - } else { - if (mOutgoingRoomKeyRequestsFileTmp.exists()) { - mOutgoingRoomKeyRequestsFileTmp.renameTo(mOutgoingRoomKeyRequestsFile); - } - } - } - - @Override - public OutgoingRoomKeyRequest getOutgoingRoomKeyRequest(Map requestBody) { - if (null != requestBody) { - return mOutgoingRoomKeyRequests.get(requestBody); - } - - return null; - } - - @Override - public OutgoingRoomKeyRequest getOrAddOutgoingRoomKeyRequest(OutgoingRoomKeyRequest request) { - // sanity check - if ((null == request) || (null == request.mRequestBody)) { - return null; - } - - // already known - if (mOutgoingRoomKeyRequests.containsKey(request.mRequestBody)) { - Log.d(LOG_TAG, "## getOrAddOutgoingRoomKeyRequest() : `already have key request outstanding for " + request.getRoomId() + " / " - + request.getSessionId() + " not sending another"); - return mOutgoingRoomKeyRequests.get(request.mRequestBody); - } else { - mOutgoingRoomKeyRequests.put(request.mRequestBody, request); - saveOutgoingRoomKeyRequests(); - return request; - } - } - - /** - * Retrieve a OutgoingRoomKeyRequest from a transaction id. - * - * @param txId the transaction id. - * @return the matched OutgoingRoomKeyRequest or null - */ - private OutgoingRoomKeyRequest getOutgoingRoomKeyRequestByTxId(String txId) { - if (null != txId) { - Collection requests = mOutgoingRoomKeyRequests.values(); - - for (OutgoingRoomKeyRequest request : requests) { - if (TextUtils.equals(request.mRequestId, txId)) { - return request; - } - } - } - - return null; - } - - /** - * Look for room key requests by state. - * - * @param states the states - * @return an OutgoingRoomKeyRequest or null - */ - @Override - public OutgoingRoomKeyRequest getOutgoingRoomKeyRequestByState(Set states) { - Collection requests = mOutgoingRoomKeyRequests.values(); - - for (OutgoingRoomKeyRequest request : requests) { - if (states.contains(request.mState)) { - return request; - } - } - - return null; - } - - @Override - public void updateOutgoingRoomKeyRequest(OutgoingRoomKeyRequest req) { - if (null != req) { - saveOutgoingRoomKeyRequests(); - } - } - - @Override - public void deleteOutgoingRoomKeyRequest(String transactionId) { - OutgoingRoomKeyRequest request = getOutgoingRoomKeyRequestByTxId(transactionId); - - if (null != request) { - mOutgoingRoomKeyRequests.remove(request.mRequestBody); - saveOutgoingRoomKeyRequests(); - } - } - - /** - * Reset the crypto store data - */ - private void resetData() { - close(); - - // ensure there is background writings while deleting the store - synchronized (LOG_TAG) { - deleteStore(); - } - - if (!mStoreFile.exists()) { - mStoreFile.mkdirs(); - } - - if (!mDevicesFolder.exists()) { - mDevicesFolder.mkdirs(); - } - - if (!mOlmSessionsFolder.exists()) { - mOlmSessionsFolder.mkdir(); - } - - if (!mInboundGroupSessionsFolder.exists()) { - mInboundGroupSessionsFolder.mkdirs(); - } - - mMetaData = null; - } - - /** - * Load a file from the crypto store - * - * @param file the file to read - * @param description the operation description - * @return the read object, null if it fails - */ - private Object loadObject(File file, String description) { - Object object = null; - - - if (file.exists()) { - try { - // the files are now zipped to reduce saving time - FileInputStream fis = new FileInputStream(file); - InputStream cis; - if (mEnableFileEncryption) { - cis = CompatUtil.createCipherInputStream(fis, mContext); - - if (cis == null) { - // fallback to unencrypted stream for backward compatibility - Log.i(LOG_TAG, "## loadObject() : failed to read encrypted, fallback to unencrypted read"); - fis.close(); - cis = new FileInputStream(file); - } - } else { - cis = fis; - } - - GZIPInputStream gz = new GZIPInputStream(cis); - ObjectInputStream ois = new ObjectInputStream(gz); - - object = ois.readObject(); - ois.close(); - } catch (Exception e) { - Log.e(LOG_TAG, description + "failed : " + e.getMessage() + " step 1", e); - - // if the zip deflating fails, try to use the former file saving method - try { - FileInputStream fis2 = new FileInputStream(file); - ObjectInputStream out = new ObjectInputStream(fis2); - - object = out.readObject(); - out.close(); - } catch (Exception subEx) { - // warn that some file loading fails - mIsCorrupted = true; - Log.e(LOG_TAG, description + "failed : " + subEx.getMessage() + " step 2", subEx); - } - } - } - return object; - } - - - /** - * Load the metadata from the store - */ - private void loadMetaData() { - Object metadataAsVoid; - - if (mMetaDataFileTmp.exists()) { - metadataAsVoid = loadObject(mMetaDataFileTmp, "loadMetadata"); - } else { - metadataAsVoid = loadObject(mMetaDataFile, "loadMetadata"); - } - - if (null != metadataAsVoid) { - try { - if (metadataAsVoid instanceof MXFileCryptoStoreMetaData2) { - mMetaData = (MXFileCryptoStoreMetaData2) metadataAsVoid; - } else { - mMetaData = new MXFileCryptoStoreMetaData2((MXFileCryptoStoreMetaData) metadataAsVoid); - } - } catch (Exception e) { - mIsCorrupted = true; - Log.e(LOG_TAG, "## loadMetadata() : metadata has been corrupted " + e.getMessage(), e); - } - } - } - - /** - * Preload the crypto data - */ - private void preloadCryptoData() { - Log.d(LOG_TAG, "## preloadCryptoData() starts"); - - long t0 = System.currentTimeMillis(); - Object olmAccountAsVoid; - - if (mAccountFileTmp.exists()) { - olmAccountAsVoid = loadObject(mAccountFileTmp, "preloadCryptoData - mAccountFile - tmp"); - } else { - olmAccountAsVoid = loadObject(mAccountFile, "preloadCryptoData - mAccountFile"); - } - - if (null != olmAccountAsVoid) { - try { - mOlmAccount = (OlmAccount) olmAccountAsVoid; - } catch (Exception e) { - mIsCorrupted = true; - Log.e(LOG_TAG, "## preloadCryptoData() - invalid mAccountFile " + e.getMessage(), e); - } - } - - Log.d(LOG_TAG, "## preloadCryptoData() : load mOlmAccount in " + (System.currentTimeMillis() - t0) + " ms"); - - // previous store format - if (!mDevicesFolder.exists()) { - Object usersDevicesInfoMapAsVoid; - - // if the tmp exists, it means that the latest file backup has been killed / stopped - if (mDevicesFileTmp.exists()) { - usersDevicesInfoMapAsVoid = loadObject(mDevicesFileTmp, "preloadCryptoData - mUsersDevicesInfoMap - tmp"); - } else { - usersDevicesInfoMapAsVoid = loadObject(mDevicesFile, "preloadCryptoData - mUsersDevicesInfoMap"); - } - - if (null != usersDevicesInfoMapAsVoid) { - try { - MXUsersDevicesMap objectAsMap = (MXUsersDevicesMap) usersDevicesInfoMapAsVoid; - mUsersDevicesInfoMap = new MXUsersDevicesMap<>(objectAsMap.getMap()); - } catch (Exception e) { - mIsCorrupted = true; - Log.e(LOG_TAG, "## preloadCryptoData() - invalid mUsersDevicesInfoMap " + e.getMessage(), e); - } - } else { - mIsCorrupted = false; - } - - mDevicesFolder.mkdirs(); - - if (null != mUsersDevicesInfoMap) { - Map> map = mUsersDevicesInfoMap.getMap(); - - Set userIds = map.keySet(); - - for (String userId : userIds) { - storeObject(map.get(userId), mDevicesFolder, userId, "convert devices map of " + userId); - } - - mDevicesFileTmp.delete(); - mDevicesFile.delete(); - } - } else { - // the user devices are loaded on demand - mUsersDevicesInfoMap = new MXUsersDevicesMap<>(); - } - - long t2 = System.currentTimeMillis(); - int algoSize = 0; - - Object algorithmsAsVoid; - - if (mAlgorithmsFileTmp.exists()) { - algorithmsAsVoid = loadObject(mAlgorithmsFileTmp, "preloadCryptoData - mRoomsAlgorithms - tmp"); - } else { - algorithmsAsVoid = loadObject(mAlgorithmsFile, "preloadCryptoData - mRoomsAlgorithms"); - } - - if (null != algorithmsAsVoid) { - try { - Map algorithmsMap = (Map) algorithmsAsVoid; - mRoomsAlgorithms = new HashMap<>(algorithmsMap); - algoSize = mRoomsAlgorithms.size(); - } catch (Exception e) { - mIsCorrupted = true; - Log.e(LOG_TAG, "## preloadCryptoData() - invalid mAlgorithmsFile " + e.getMessage(), e); - } - } - Log.d(LOG_TAG, "## preloadCryptoData() : load mRoomsAlgorithms (" + algoSize + " algos) in " + (System.currentTimeMillis() - t2) + " ms"); - - Object trackingStatusesAsVoid; - - if (mTrackingStatusesFileTmp.exists()) { - trackingStatusesAsVoid = loadObject(mTrackingStatusesFileTmp, "preloadCryptoData - mTrackingStatuses - tmp"); - } else { - trackingStatusesAsVoid = loadObject(mTrackingStatusesFile, "preloadCryptoData - mTrackingStatuses"); - } - - if (null != trackingStatusesAsVoid) { - try { - mTrackingStatuses = new HashMap<>((Map) trackingStatusesAsVoid); - } catch (Exception e) { - Log.e(LOG_TAG, "## preloadCryptoData() - invalid mTrackingStatuses " + e.getMessage(), e); - } - } - - File outgoingRequestFile; - if (mOutgoingRoomKeyRequestsFileTmp.exists()) { - outgoingRequestFile = mOutgoingRoomKeyRequestsFileTmp; - } else { - outgoingRequestFile = mOutgoingRoomKeyRequestsFile; - } - - if (outgoingRequestFile.exists()) { - Object requestsAsVoid = loadObject(outgoingRequestFile, "get outgoing key request"); - try { - if (null != requestsAsVoid) { - mOutgoingRoomKeyRequests.putAll((Map, OutgoingRoomKeyRequest>) requestsAsVoid); - } - } catch (Exception e) { - Log.e(LOG_TAG, "## preloadCryptoData() : mOutgoingRoomKeyRequests init failed " + e.getMessage(), e); - } - } - - if (mOlmSessionsFolder.exists()) { - long t3 = System.currentTimeMillis(); - - mOlmSessions = new HashMap<>(); - - String[] olmSessionFiles = mOlmSessionsFolder.list(); - - if (null != olmSessionFiles) { - // build mOlmSessions for the file system - for (int i = 0; i < olmSessionFiles.length; i++) { - String deviceKey = olmSessionFiles[i]; - - Map olmSessionSubMap = new HashMap<>(); - - File sessionsDeviceFolder = new File(mOlmSessionsFolder, deviceKey); - String[] sessionIds = sessionsDeviceFolder.list(); - - if (null != sessionIds) { - for (int j = 0; j < sessionIds.length; j++) { - String sessionId = sessionIds[j]; - OlmSession olmSession = (OlmSession) loadObject(new File(sessionsDeviceFolder, sessionId), "load the olmSession " - + deviceKey + " " + sessionId); - - if (null != olmSession) { - olmSessionSubMap.put(decodeFilename(sessionId), olmSession); - } - } - } - mOlmSessions.put(decodeFilename(deviceKey), olmSessionSubMap); - } - - Log.d(LOG_TAG, "## preloadCryptoData() : load " + olmSessionFiles.length + " olmsessions in " + (System.currentTimeMillis() - t3) + " ms"); - } - } else { - Object olmSessionsAsVoid; - - if (mOlmSessionsFileTmp.exists()) { - olmSessionsAsVoid = loadObject(mOlmSessionsFileTmp, "preloadCryptoData - mOlmSessions - tmp"); - } else { - olmSessionsAsVoid = loadObject(mOlmSessionsFile, "preloadCryptoData - mOlmSessions"); - } - - if (null != olmSessionsAsVoid) { - try { - Map> olmSessionMap = (Map>) olmSessionsAsVoid; - - mOlmSessions = new HashMap<>(); - - for (String key : olmSessionMap.keySet()) { - mOlmSessions.put(key, new HashMap<>(olmSessionMap.get(key))); - } - - // convert to the new format - if (!mOlmSessionsFolder.mkdir()) { - Log.e(LOG_TAG, "Cannot create the folder " + mOlmSessionsFolder); - } - - for (String key : olmSessionMap.keySet()) { - Map submap = olmSessionMap.get(key); - - File submapFolder = new File(mOlmSessionsFolder, encodeFilename(key)); - - if (!submapFolder.mkdir()) { - Log.e(LOG_TAG, "Cannot create the folder " + submapFolder); - } - - for (String sessionId : submap.keySet()) { - storeObject(submap.get(sessionId), submapFolder, encodeFilename(sessionId), "Convert olmSession " + key + " " + sessionId); - } - } - } catch (Exception e) { - mIsCorrupted = true; - Log.e(LOG_TAG, "## preloadCryptoData() - invalid mSessionsFile " + e.getMessage(), e); - } - - mOlmSessionsFileTmp.delete(); - mOlmSessionsFile.delete(); - } - } - - if (mInboundGroupSessionsFolder.exists()) { - long t4 = System.currentTimeMillis(); - mInboundGroupSessions = new HashMap<>(); - - int count = 0; - - String[] keysFolder = mInboundGroupSessionsFolder.list(); - - if (null != keysFolder) { - for (int i = 0; i < keysFolder.length; i++) { - File keyFolder = new File(mInboundGroupSessionsFolder, keysFolder[i]); - - Map submap = new HashMap<>(); - - String[] sessionIds = keyFolder.list(); - - if (null != sessionIds) { - for (int j = 0; j < sessionIds.length; j++) { - File inboundSessionFile = new File(keyFolder, sessionIds[j]); - try { - Object inboundSessionAsVoid = loadObject(inboundSessionFile, "load inboundsession " + sessionIds[j] + " "); - MXOlmInboundGroupSession2 inboundSession; - - if ((null != inboundSessionAsVoid) && (inboundSessionAsVoid instanceof MXOlmInboundGroupSession)) { - inboundSession = new MXOlmInboundGroupSession2((MXOlmInboundGroupSession) inboundSessionAsVoid); - } else { - inboundSession = (MXOlmInboundGroupSession2) inboundSessionAsVoid; - } - - if (null != inboundSession) { - submap.put(decodeFilename(sessionIds[j]), inboundSession); - } else { - Log.e(LOG_TAG, "## preloadCryptoData() : delete " + inboundSessionFile); - inboundSessionFile.delete(); - mIsCorrupted = false; - } - count++; - } catch (Exception e) { - Log.e(LOG_TAG, "## preloadCryptoData() - invalid mInboundGroupSessions " + e.getMessage(), e); - } - } - } - - mInboundGroupSessions.put(decodeFilename(keysFolder[i]), submap); - } - } - - Log.d(LOG_TAG, "## preloadCryptoData() : load " + count + " inboundGroupSessions in " + (System.currentTimeMillis() - t4) + " ms"); - } else { - Object inboundGroupSessionsAsVoid; - - if (mInboundGroupSessionsFileTmp.exists()) { - inboundGroupSessionsAsVoid = loadObject(mInboundGroupSessionsFileTmp, "preloadCryptoData - mInboundGroupSessions - tmp"); - } else { - inboundGroupSessionsAsVoid = loadObject(mInboundGroupSessionsFile, "preloadCryptoData - mInboundGroupSessions"); - } - - if (null != inboundGroupSessionsAsVoid) { - try { - Map> inboundGroupSessionsMap - = (Map>) inboundGroupSessionsAsVoid; - - mInboundGroupSessions = new HashMap<>(); - - for (String key : inboundGroupSessionsMap.keySet()) { - mInboundGroupSessions.put(key, new HashMap<>(inboundGroupSessionsMap.get(key))); - } - } catch (Exception e) { - mIsCorrupted = true; - Log.e(LOG_TAG, "## preloadCryptoData() - invalid mInboundGroupSessions " + e.getMessage(), e); - } - - if (!mInboundGroupSessionsFolder.mkdirs()) { - Log.e(LOG_TAG, "Cannot create the folder " + mInboundGroupSessionsFolder); - } - - // convert to the new format - for (String key : mInboundGroupSessions.keySet()) { - File keyFolder = new File(mInboundGroupSessionsFolder, encodeFilename(key)); - - if (!keyFolder.mkdirs()) { - Log.e(LOG_TAG, "Cannot create the folder " + keyFolder); - } - - Map inboundMaps = mInboundGroupSessions.get(key); - - for (String sessionId : inboundMaps.keySet()) { - storeObject(inboundMaps.get(sessionId), keyFolder, encodeFilename(sessionId), "Convert inboundsession"); - } - } - } - - mInboundGroupSessionsFileTmp.delete(); - mInboundGroupSessionsFile.delete(); - } - - if ((null == mOlmAccount) && (mUsersDevicesInfoMap.getMap().size() > 0)) { - mIsCorrupted = true; - Log.e(LOG_TAG, "## preloadCryptoData() - there is no account but some devices are defined"); - } - } - - final private static char[] hexArray = "0123456789ABCDEF".toCharArray(); - - /** - * Encode the provided filename - * - * @param filename the filename to encode - * @return the encoded filename - */ - private static String encodeFilename(String filename) { - if (null == filename) { - return null; - } - - try { - byte[] bytes = filename.getBytes("UTF-8"); - char[] hexChars = new char[bytes.length * 2]; - - for (int j = 0; j < bytes.length; j++) { - int v = bytes[j] & 0xFF; - hexChars[j * 2] = hexArray[v >>> 4]; - hexChars[j * 2 + 1] = hexArray[v & 0x0F]; - } - return new String(hexChars); - } catch (Exception e) { - Log.e(LOG_TAG, "## encodeFilename() - failed " + e.getMessage(), e); - } - - return filename; - } - - /** - * Decode an encoded filename. - * - * @param encodedFilename the encoded filename - * @return the decodec filename - */ - private static String decodeFilename(String encodedFilename) { - if (null == encodedFilename) { - return null; - } - - int length = encodedFilename.length(); - - byte[] bytes = new byte[length / 2]; - - for (int i = 0; i < length; i += 2) { - bytes[i / 2] = (byte) ((Character.digit(encodedFilename.charAt(i), 16) << 4) - + Character.digit(encodedFilename.charAt(i + 1), 16)); - } - - try { - return new String(bytes, "UTF-8"); - } catch (Exception e) { - Log.e(LOG_TAG, "## decodeFilename() - failed " + e.getMessage(), e); - } - - return encodedFilename; - } - - - /** - * Tells if an IncomingRoomKeyRequest instance is valid - * - * @param incomingRoomKeyRequest the incomingRoomKeyRequest instance - * @return true if it is valid - */ - private boolean isValidIncomingRoomKeyRequest(IncomingRoomKeyRequest incomingRoomKeyRequest) { - return (null != incomingRoomKeyRequest) - && !TextUtils.isEmpty(incomingRoomKeyRequest.mUserId) - && !TextUtils.isEmpty(incomingRoomKeyRequest.mDeviceId) - && !TextUtils.isEmpty(incomingRoomKeyRequest.mRequestId); - } - - @Override - public IncomingRoomKeyRequest getIncomingRoomKeyRequest(String userId, String deviceId, String requestId) { - // sanity checks - if (TextUtils.isEmpty(userId) || TextUtils.isEmpty(deviceId) || TextUtils.isEmpty(requestId)) { - return null; - } - - if (!mPendingIncomingRoomKeyRequests.containsKey(userId)) { - return null; - } - - if (!mPendingIncomingRoomKeyRequests.get(userId).containsKey(deviceId)) { - return null; - } - - List pendingRequests = mPendingIncomingRoomKeyRequests.get(userId).get(deviceId); - - for (IncomingRoomKeyRequest request : pendingRequests) { - if (TextUtils.equals(requestId, request.mRequestId)) { - return request; - } - } - - return null; - } - - @Override - public List getPendingIncomingRoomKeyRequests() { - loadIncomingRoomKeyRequests(); - - List list = new ArrayList<>(); - - // userId -> deviceId -> [keyRequest] - Set userIds = mPendingIncomingRoomKeyRequests.keySet(); - - for (String userId : userIds) { - Set deviceIds = mPendingIncomingRoomKeyRequests.get(userId).keySet(); - for (String deviceId : deviceIds) { - list.addAll(mPendingIncomingRoomKeyRequests.get(userId).get(deviceId)); - } - } - - return list; - } - - /** - * Add an incomingRoomKeyRequest. - * - * @param incomingRoomKeyRequest the incomingRoomKeyRequest request - */ - private void addIncomingRoomKeyRequest(IncomingRoomKeyRequest incomingRoomKeyRequest) { - String userId = incomingRoomKeyRequest.mUserId; - String deviceId = incomingRoomKeyRequest.mDeviceId; - - if (!mPendingIncomingRoomKeyRequests.containsKey(userId)) { - mPendingIncomingRoomKeyRequests.put(userId, new HashMap>()); - } - - if (!mPendingIncomingRoomKeyRequests.get(userId).containsKey(deviceId)) { - mPendingIncomingRoomKeyRequests.get(userId).put(deviceId, new ArrayList()); - } - - mPendingIncomingRoomKeyRequests.get(userId).get(deviceId).add(incomingRoomKeyRequest); - } - - @Override - public void storeIncomingRoomKeyRequest(IncomingRoomKeyRequest incomingRoomKeyRequest) { - loadIncomingRoomKeyRequests(); - - // invalid or already stored - if (!isValidIncomingRoomKeyRequest(incomingRoomKeyRequest) - || (null != getIncomingRoomKeyRequest(incomingRoomKeyRequest.mUserId, incomingRoomKeyRequest.mDeviceId, incomingRoomKeyRequest.mRequestId))) { - return; - } - - addIncomingRoomKeyRequest(incomingRoomKeyRequest); - saveIncomingRoomKeyRequests(); - } - - @Override - public void deleteIncomingRoomKeyRequest(IncomingRoomKeyRequest incomingRoomKeyRequest) { - loadIncomingRoomKeyRequests(); - - if (!isValidIncomingRoomKeyRequest(incomingRoomKeyRequest)) { - return; - } - - IncomingRoomKeyRequest request = getIncomingRoomKeyRequest(incomingRoomKeyRequest.mUserId, - incomingRoomKeyRequest.mDeviceId, incomingRoomKeyRequest.mRequestId); - - if (null == request) { - return; - } - - String userId = incomingRoomKeyRequest.mUserId; - String deviceId = incomingRoomKeyRequest.mDeviceId; - - mPendingIncomingRoomKeyRequests.get(userId).get(deviceId).remove(request); - - if (mPendingIncomingRoomKeyRequests.get(userId).get(deviceId).isEmpty()) { - mPendingIncomingRoomKeyRequests.get(userId).remove(deviceId); - } - - if (mPendingIncomingRoomKeyRequests.get(userId).isEmpty()) { - mPendingIncomingRoomKeyRequests.remove(userId); - } - - saveIncomingRoomKeyRequests(); - } - - /** - * Save the incoming key requests - */ - private void saveIncomingRoomKeyRequests() { - // delete the previous tmp - if (mIncomingRoomKeyRequestsFileTmp.exists()) { - mIncomingRoomKeyRequestsFileTmp.delete(); - } - - // copy the existing file - if (mIncomingRoomKeyRequestsFile.exists()) { - mIncomingRoomKeyRequestsFile.renameTo(mIncomingRoomKeyRequestsFileTmp); - } - - if (storeObject(getPendingIncomingRoomKeyRequests(), mIncomingRoomKeyRequestsFile, "savedIncomingRoomKeyRequests - in background")) { - // remove the tmp file - if (mIncomingRoomKeyRequestsFileTmp.exists()) { - mIncomingRoomKeyRequestsFileTmp.delete(); - } - } else { - if (mIncomingRoomKeyRequestsFileTmp.exists()) { - mIncomingRoomKeyRequestsFileTmp.renameTo(mIncomingRoomKeyRequestsFile); - } - } - } - - /** - * Load the incoming key requests - */ - private void loadIncomingRoomKeyRequests() { - if (null == mPendingIncomingRoomKeyRequests) { - Object requestsAsVoid; - - if (mIncomingRoomKeyRequestsFileTmp.exists()) { - requestsAsVoid = loadObject(mIncomingRoomKeyRequestsFileTmp, "loadIncomingRoomKeyRequests - tmp"); - } else { - requestsAsVoid = loadObject(mIncomingRoomKeyRequestsFile, "loadIncomingRoomKeyRequests"); - } - - List requests = new ArrayList<>(); - - if (null != requestsAsVoid) { - try { - requests = (List) requestsAsVoid; - } catch (Exception e) { - mIncomingRoomKeyRequestsFileTmp.delete(); - mIncomingRoomKeyRequestsFile.delete(); - } - } - - mPendingIncomingRoomKeyRequests = new HashMap<>(); - - for (IncomingRoomKeyRequest request : requests) { - addIncomingRoomKeyRequest(request); - } - } - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/cryptostore/MXFileCryptoStoreMetaData.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/cryptostore/MXFileCryptoStoreMetaData.java deleted file mode 100644 index 19dbdf63..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/cryptostore/MXFileCryptoStoreMetaData.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2015 OpenMarket 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.matrix.android.internal.legacy.data.cryptostore; - -public class MXFileCryptoStoreMetaData implements java.io.Serializable { - // The obtained user id. - public String mUserId; - - // the device id - public String mDeviceId; - - // The current version of the store. - public int mVersion; - - // flag to tell if the device is announced - public boolean mDeviceAnnounced; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/cryptostore/MXFileCryptoStoreMetaData2.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/cryptostore/MXFileCryptoStoreMetaData2.java deleted file mode 100644 index ad1dee99..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/cryptostore/MXFileCryptoStoreMetaData2.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.data.cryptostore; - -import java.util.ArrayList; -import java.util.List; - -public class MXFileCryptoStoreMetaData2 implements java.io.Serializable { - // avoid creating another MXFileCryptoStoreMetaData3 - // set a serialVersionUID allows to update the class. - private static final long serialVersionUID = 9166554107081078408L; - - // The obtained user id. - public String mUserId; - - // the device id - public String mDeviceId; - - // The current version of the store. - public int mVersion; - - // flag to tell if the device is announced - // not anymore used - public boolean mDeviceAnnounced; - - // flag to tell if the unverified devices are blacklisted for any room. - public boolean mGlobalBlacklistUnverifiedDevices; - - // Room ids list in which the unverified devices are blacklisted - public List mBlacklistUnverifiedDevicesRoomIdsList; - - /** - * Default constructor - * - * @param userId the user id - * @param deviceId the device id - * @param version the version - */ - public MXFileCryptoStoreMetaData2(String userId, String deviceId, int version) { - mUserId = new String(userId); - mDeviceId = (null != deviceId) ? new String(deviceId) : null; - mVersion = version; - mDeviceAnnounced = false; - mGlobalBlacklistUnverifiedDevices = false; - mBlacklistUnverifiedDevicesRoomIdsList = new ArrayList<>(); - } - - /** - * Constructor with the genuine metadata format data. - * - * @param metadata the genuine metadata format data. - */ - public MXFileCryptoStoreMetaData2(MXFileCryptoStoreMetaData metadata) { - mUserId = metadata.mUserId; - mDeviceId = metadata.mDeviceId; - mVersion = metadata.mVersion; - mDeviceAnnounced = metadata.mDeviceAnnounced; - mGlobalBlacklistUnverifiedDevices = false; - mBlacklistUnverifiedDevicesRoomIdsList = new ArrayList<>(); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/metrics/MetricsListener.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/metrics/MetricsListener.java deleted file mode 100644 index da483353..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/metrics/MetricsListener.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.data.metrics; - -/** - * This interface defines methods for collecting metrics data associated with startup times and stats - * Those callbacks can be called from any threads - */ -public interface MetricsListener { - - /** - * Called when the initial sync is finished - * - * @param duration of the sync - */ - void onInitialSyncFinished(long duration); - - /** - * Called when the incremental sync is finished - * - * @param duration of the sync - */ - void onIncrementalSyncFinished(long duration); - - /** - * Called when a store is preloaded - * - * @param duration of the preload - */ - void onStorePreloaded(long duration); - - /** - * Called when a sync is complete - * - * @param nbOfRooms loaded in the @SyncResponse - */ - void onRoomsLoaded(int nbOfRooms); - -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/store/IMXStore.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/store/IMXStore.java deleted file mode 100644 index c8efaaff..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/store/IMXStore.java +++ /dev/null @@ -1,645 +0,0 @@ -/* - * Copyright 2015 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.data.store; - -import android.content.Context; -import android.support.annotation.Nullable; - -import im.vector.matrix.android.internal.legacy.data.timeline.EventTimeline; -import im.vector.matrix.android.internal.legacy.data.Room; -import im.vector.matrix.android.internal.legacy.data.RoomAccountData; -import im.vector.matrix.android.internal.legacy.data.RoomSummary; -import im.vector.matrix.android.internal.legacy.data.metrics.MetricsListener; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.ReceiptData; -import im.vector.matrix.android.internal.legacy.rest.model.RoomMember; -import im.vector.matrix.android.internal.legacy.rest.model.TokensChunkEvents; -import im.vector.matrix.android.internal.legacy.rest.model.User; -import im.vector.matrix.android.internal.legacy.rest.model.group.Group; -import im.vector.matrix.android.internal.legacy.rest.model.pid.ThirdPartyIdentifier; - -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * An interface for storing and retrieving Matrix objects. - */ -public interface IMXStore { - /** - * Save changes in the store. - * If the store uses permanent storage like database or file, it is the optimised time - * to commit the last changes. - */ - void commit(); - - /** - * Open the store. - */ - void open(); - - /** - * Close the store. - * Any pending operation must be complete in this call. - */ - void close(); - - /** - * Clear the store. - * Any pending operation must be complete in this call. - */ - void clear(); - - /** - * @return the used context - */ - Context getContext(); - - /** - * Indicate if the MXStore implementation stores data permanently. - * Permanent storage allows the SDK to make less requests at the startup. - * - * @return true if permanent. - */ - boolean isPermanent(); - - /** - * Check if the initial load is performed. - * - * @return true if it is ready. - */ - boolean isReady(); - - /** - * Check if the read receipts are ready to be used. - * - * @return true if they are ready. - */ - boolean areReceiptsReady(); - - /** - * @return true if the store is corrupted. - */ - boolean isCorrupted(); - - /** - * Warn that the store data are corrupted. - * It might append if an update request failed. - * - * @param reason the corruption reason - */ - void setCorrupted(String reason); - - /** - * Returns to disk usage size in bytes. - * - * @return disk usage size - */ - long diskUsage(); - - /** - * Returns the latest known event stream token - * - * @return the event stream token - */ - String getEventStreamToken(); - - /** - * Set the event stream token. - * - * @param token the event stream token - */ - void setEventStreamToken(String token); - - /** - * Add a MXStore listener. - * - * @param listener the listener - */ - void addMXStoreListener(IMXStoreListener listener); - - /** - * remove a MXStore listener. - * - * @param listener the listener - */ - void removeMXStoreListener(IMXStoreListener listener); - - /** - * @return the display name - */ - String displayName(); - - /** - * Update the user display name - * - * @param displayName the displayname - * @param ts the timestamp update - * @return true if there is an update - */ - boolean setDisplayName(String displayName, long ts); - - /** - * @return the avatar URL - */ - String avatarURL(); - - /** - * Update the avatar URL - * - * @param avatarURL the new URL - * @param ts the timestamp update - * @return true if there is an update - */ - boolean setAvatarURL(String avatarURL, long ts); - - /** - * @return the third party identifiers list - */ - List thirdPartyIdentifiers(); - - /** - * Update the third party identifiers list. - * - * @param identifiers the identifiers list - */ - void setThirdPartyIdentifiers(List identifiers); - - /** - * Update the ignored user ids list. - * - * @param users the user ids list - */ - void setIgnoredUserIdsList(List users); - - /** - * Update the direct chat rooms list - * - * @param directChatRoomsDict the direct chats map - */ - void setDirectChatRoomsDict(Map> directChatRoomsDict); - - /** - * @return the known rooms list - */ - Collection getRooms(); - - /** - * Retrieve a room from its room id - * - * @param roomId the room id - * @return the room if it exists - */ - Room getRoom(String roomId); - - /** - * @return the known users lists - */ - Collection getUsers(); - - /** - * Retrieves an user by its user id. - * - * @param userId the user id - * @return the user - */ - User getUser(String userId); - - /** - * @return the ignored user ids list - */ - List getIgnoredUserIdsList(); - - /** - * @return the direct chats rooms list - */ - Map> getDirectChatRoomsDict(); - - /** - * Flush an updated user. - * - * @param user the user - */ - void storeUser(User user); - - /** - * Flush an user from a room member. - * - * @param roomMember the room member - */ - void updateUserWithRoomMemberEvent(RoomMember roomMember); - - /** - * Flush a room. - * - * @param room the room - */ - void storeRoom(Room room); - - /** - * Store a block of room events either live or from pagination. - * - * @param roomId the room id - * @param tokensChunkEvents the events to be stored. - * @param direction the direction; forwards for live, backwards for pagination - */ - void storeRoomEvents(String roomId, TokensChunkEvents tokensChunkEvents, EventTimeline.Direction direction); - - /** - * Store the back token of a room. - * - * @param roomId the room id. - * @param backToken the back token - */ - void storeBackToken(String roomId, String backToken); - - /** - * Store a live room event. - * - * @param event The event to be stored. - */ - void storeLiveRoomEvent(Event event); - - /** - * @param eventId the id of the event to retrieve. - * @param roomId the id of the room. - * @return true if the event exists in the store. - */ - boolean doesEventExist(String eventId, String roomId); - - /** - * Retrieve an event from its room Id and its Event id - * - * @param eventId the event id - * @param roomId the room Id - * @return the event (null if it is not found) - */ - Event getEvent(String eventId, String roomId); - - /** - * Delete an event - * - * @param event The event to be deleted. - */ - void deleteEvent(Event event); - - /** - * Remove all sent messages in a room. - * - * @param roomId the id of the room. - * @param keepUnsent set to true to do not delete the unsent message - */ - void deleteAllRoomMessages(String roomId, boolean keepUnsent); - - /** - * Flush the room events. - * - * @param roomId the id of the room. - */ - void flushRoomEvents(String roomId); - - /** - * Delete the room from the storage. - * The room data and its reference will be deleted. - * - * @param roomId the roomId. - */ - void deleteRoom(String roomId); - - /** - * Delete the room data from the storage; - * The room data are cleared but the getRoom returned object will be the same. - * - * @param roomId the roomId. - */ - void deleteRoomData(String roomId); - - /** - * Retrieve all non-state room events for this room. - * - * @param roomId The room ID - * @return A collection of events. null if there is no cached event. - */ - Collection getRoomMessages(final String roomId); - - /** - * Retrieve all non-state room events for this room. - * - * @param roomId The room ID - * @param fromToken the token - * @param limit the maximum number of messages to retrieve. - * @return A collection of events. null if there is no cached event. - */ - TokensChunkEvents getEarlierMessages(final String roomId, final String fromToken, final int limit); - - /** - * Get the oldest event from the given room (to prevent pagination overlap). - * - * @param roomId the room id - * @return the event - */ - Event getOldestEvent(String roomId); - - /** - * Get the latest event from the given room (to update summary for example) - * - * @param roomId the room id - * @return the event - */ - Event getLatestEvent(String roomId); - - /** - * Count the number of events after the provided events id - * - * @param roomId the room id. - * @param eventId the event id to find. - * @return the events count after this event if - */ - int eventsCountAfter(String roomId, String eventId); - - // Design note: This is part of the store interface so the concrete implementation can leverage - // how they are storing the data to do this in an efficient manner (e.g. SQL JOINs) - // compared to calling getRooms() then getRoomEvents(roomId, limit=1) for each room - // (which forces single SELECTs) - - /** - *

Retrieve a list of all the room summaries stored.

- * Typically this method will be called when generating a 'Recent Activity' list. - * - * @return A collection of room summaries. - */ - Collection getSummaries(); - - /** - * Get the stored summary for the given room. - * - * @param roomId the room id - * @return the summary for the room, or null in case of error - */ - @Nullable - RoomSummary getSummary(String roomId); - - /** - * Flush a room summary - * - * @param summary the summary. - */ - void flushSummary(RoomSummary summary); - - /** - * Flush the room summaries - */ - void flushSummaries(); - - /** - * Store a new summary. - * - * @param summary the summary - */ - void storeSummary(RoomSummary summary); - - /** - * Store the room liveState. - * - * @param roomId roomId the id of the room. - */ - void storeLiveStateForRoom(String roomId); - - /** - * Store a room state event. - * The room states are built with several events. - * - * @param roomId the room id - * @param event the event - */ - void storeRoomStateEvent(String roomId, im.vector.matrix.android.api.session.events.model.Event event); - - /** - * Retrieve the room state creation events - * - * @param roomId the room id - * @param callback the asynchronous callback - */ - void getRoomStateEvents(String roomId, ApiCallback> callback); - - /** - * Return the list of latest unsent events. - * The provided events are the unsent ones since the last sent one. - * They are ordered. - * - * @param roomId the room id - * @return list of unsent events - */ - List getLatestUnsentEvents(String roomId); - - /** - * Return the list of undelivered events - * - * @param roomId the room id - * @return list of undelivered events - */ - List getUndeliveredEvents(String roomId); - - /** - * Return the list of unknown device events. - * - * @param roomId the room id - * @return list of unknown device events - */ - List getUnknownDeviceEvents(String roomId); - - /** - * Returns the receipts list for an event in a dedicated room. - * if sort is set to YES, they are sorted from the latest to the oldest ones. - * - * @param roomId The room Id. - * @param eventId The event Id. (null to retrieve all existing receipts) - * @param excludeSelf exclude the oneself read receipts. - * @param sort to sort them from the latest to the oldest - * @return the receipts for an event in a dedicated room. - */ - List getEventReceipts(String roomId, String eventId, boolean excludeSelf, boolean sort); - - /** - * Store the receipt for an user in a room. - * The receipt validity is checked i.e the receipt is not for an already read message. - * - * @param receipt The event - * @param roomId The roomId - * @return true if the receipt has been stored - */ - boolean storeReceipt(ReceiptData receipt, String roomId); - - /** - * Get the receipt for an user in a dedicated room. - * - * @param roomId the room id. - * @param userId the user id. - * @return the dedicated receipt - */ - ReceiptData getReceipt(String roomId, String userId); - - /** - * Provides the unread events list. - * - * @param roomId the room id. - * @param types an array of event types strings (Event.EVENT_TYPE_XXX). - * @return the unread events list. - */ - List unreadEvents(String roomId, List types); - - /** - * Check if an event has been read by an user. - * - * @param roomId the room Id - * @param userId the user id - * @param eventId the event id - * @return true if the user has read the message. - */ - boolean isEventRead(String roomId, String userId, String eventId); - - /** - * Store the user data for a room. - * - * @param roomId The room Id. - * @param accountData the account data. - */ - void storeAccountData(String roomId, RoomAccountData accountData); - - /** - * Provides the store preload time in milliseconds. - * - * @return the store preload time in milliseconds. - */ - long getPreloadTime(); - - /** - * Provides some store stats - * - * @return the store stats - */ - Map getStats(); - - /** - * Start a runnable from the store thread - * - * @param runnable the runnable to call - */ - void post(Runnable runnable); - - /** - * Store a group - * - * @param group the group to store - */ - void storeGroup(Group group); - - /** - * Flush a group in store. - * - * @param group the group - */ - void flushGroup(Group group); - - /** - * Delete a group - * - * @param groupId the group id to delete - */ - void deleteGroup(String groupId); - - /** - * Retrieve a group from its id. - * - * @param groupId the group id - * @return the group if it exists - */ - Group getGroup(String groupId); - - /** - * @return the stored groups - */ - Collection getGroups(); - - /** - * Set the URL preview status - * - * @param value the URL preview status - */ - void setURLPreviewEnabled(boolean value); - - /** - * Tells if the global URL preview is enabled. - * - * @return true if it is enabled - */ - boolean isURLPreviewEnabled(); - - /** - * Update the rooms list which don't have URL previews - * - * @param roomIds the room ids list - */ - void setRoomsWithoutURLPreview(Set roomIds); - - /** - * Set the user widgets - */ - void setUserWidgets(Map contentDict); - - /** - * Get the user widgets - */ - Map getUserWidgets(); - - /** - * @return the room ids list which don't have URL preview enabled - */ - Set getRoomsWithoutURLPreviews(); - - /** - * Add a couple Json filter / filterId - */ - void addFilter(String jsonFilter, String filterId); - - /** - * Get the Map of all filters configured server side (note: only by this current instance of Riot) - */ - Map getFilters(); - - /** - * Set the public key of the antivirus server - */ - void setAntivirusServerPublicKey(@Nullable String key); - - /** - * @return the public key of the antivirus server - */ - @Nullable - String getAntivirusServerPublicKey(); - - /** - * Update the metrics listener - * - * @param metricsListener the metrics listener - */ - void setMetricsListener(MetricsListener metricsListener); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/store/IMXStoreListener.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/store/IMXStoreListener.java deleted file mode 100644 index 3f26bd79..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/store/IMXStoreListener.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2015 OpenMarket 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.matrix.android.internal.legacy.data.store; - -/** - * An interface for listening the store events - */ -public interface IMXStoreListener { - /** - * The store has loaded its internal data. - * Let any post processing data management. - * It is called in the store thread before calling onStoreReady. - * - * @param accountId the account id - */ - void postProcess(String accountId); - - /** - * Called when the store is initialized - * - * @param accountId the account identifier - */ - void onStoreReady(String accountId); - - /** - * Called when the store initialization fails. - * - * @param accountId the account identifier - * @param description the corruption error messages - */ - void onStoreCorrupted(String accountId, String description); - - /** - * Called when the store has no more memory - * - * @param accountId the account identifier - * @param description the corruption error messages - */ - void onStoreOOM(String accountId, String description); - - /** - * The read receipts of a room is loaded are loaded - * - * @param roomId the room id - */ - void onReadReceiptsLoaded(String roomId); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/store/MXFileStore.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/store/MXFileStore.java deleted file mode 100644 index 11e86ae4..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/store/MXFileStore.java +++ /dev/null @@ -1,2607 +0,0 @@ -/* - * Copyright 2015 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.data.store; - -import android.content.Context; -import android.os.HandlerThread; -import android.support.annotation.Nullable; -import android.text.TextUtils; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.zip.GZIPInputStream; -import java.util.zip.GZIPOutputStream; - -import im.vector.matrix.android.api.auth.data.Credentials; -import im.vector.matrix.android.internal.legacy.data.Room; -import im.vector.matrix.android.internal.legacy.data.RoomAccountData; -import im.vector.matrix.android.internal.legacy.data.RoomState; -import im.vector.matrix.android.internal.legacy.data.RoomSummary; -import im.vector.matrix.android.internal.legacy.data.timeline.EventTimeline; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.ReceiptData; -import im.vector.matrix.android.internal.legacy.rest.model.RoomMember; -import im.vector.matrix.android.internal.legacy.rest.model.TokensChunkEvents; -import im.vector.matrix.android.internal.legacy.rest.model.User; -import im.vector.matrix.android.internal.legacy.rest.model.group.Group; -import im.vector.matrix.android.internal.legacy.rest.model.pid.ThirdPartyIdentifier; -import im.vector.matrix.android.internal.legacy.util.CompatUtil; -import im.vector.matrix.android.internal.legacy.util.ContentUtils; -import im.vector.matrix.android.internal.legacy.util.Log; -import im.vector.matrix.android.internal.legacy.util.MXOsHandler; - -/** - * An in-file IMXStore. - */ -public class MXFileStore extends MXMemoryStore { - private static final String LOG_TAG = MXFileStore.class.getSimpleName(); - - // some constant values - private static final int MXFILE_VERSION = 22; - - // ensure that there is enough messages to fill a tablet screen - private static final int MAX_STORED_MESSAGES_COUNT = 50; - - private static final String MXFILE_STORE_FOLDER = "MXFileStore"; - private static final String MXFILE_STORE_METADATA_FILE_NAME = "MXFileStore"; - - private static final String MXFILE_STORE_GZ_ROOMS_MESSAGES_FOLDER = "messages_gz"; - private static final String MXFILE_STORE_ROOMS_TOKENS_FOLDER = "tokens"; - private static final String MXFILE_STORE_GZ_ROOMS_STATE_FOLDER = "state_gz"; - private static final String MXFILE_STORE_GZ_ROOMS_STATE_EVENTS_FOLDER = "state_rooms_events"; - private static final String MXFILE_STORE_ROOMS_SUMMARY_FOLDER = "summary"; - private static final String MXFILE_STORE_ROOMS_RECEIPT_FOLDER = "receipts"; - private static final String MXFILE_STORE_ROOMS_ACCOUNT_DATA_FOLDER = "accountData"; - private static final String MXFILE_STORE_USER_FOLDER = "users"; - private static final String MXFILE_STORE_GROUPS_FOLDER = "groups"; - - // the data is read from the file system - private boolean mIsReady = false; - - // tell if the post processing has been done - private boolean mIsPostProcessingDone = false; - - // the read receipts are ready - private boolean mAreReceiptsReady = false; - - // the store is currently opening - private boolean mIsOpening = false; - - // List of rooms to save on [MXStore commit] - // filled with roomId - private Set mRoomsToCommitForMessages; - private Set mRoomsToCommitForStates; - //private Set mRoomsToCommitForStatesEvents; - private Set mRoomsToCommitForSummaries; - private Set mRoomsToCommitForAccountData; - private Set mRoomsToCommitForReceipts; - private Set mUserIdsToCommit; - private Set mGroupsToCommit; - - // Flag to indicate metaData needs to be store - private boolean mMetaDataHasChanged = false; - - // The path of the MXFileStore folders - private File mStoreFolderFile = null; - private File mGzStoreRoomsMessagesFolderFile = null; - private File mStoreRoomsTokensFolderFile = null; - private File mGzStoreRoomsStateFolderFile = null; - private File mGzStoreRoomsStateEventsFolderFile = null; - private File mStoreRoomsSummaryFolderFile = null; - private File mStoreRoomsMessagesReceiptsFolderFile = null; - private File mStoreRoomsAccountDataFolderFile = null; - private File mStoreUserFolderFile = null; - private File mStoreGroupsFolderFile = null; - - // the background thread - private HandlerThread mHandlerThread = null; - private MXOsHandler mFileStoreHandler = null; - - private boolean mIsKilled = false; - - private boolean mIsNewStorage = false; - - private boolean mAreUsersLoaded = false; - - private long mPreloadTime = 0; - - // the read receipts are asynchronously loaded - // keep a list of the remaining receipts to load - private final List mRoomReceiptsToLoad = new ArrayList<>(); - - // store some stats - private final Map mStoreStats = new HashMap<>(); - - // True if file encryption is enabled - private final boolean mEnableFileEncryption; - - /** - * Create the file store dirtrees - */ - private void createDirTree(String userId) { - // data path - // MXFileStore/userID/ - // MXFileStore/userID/MXFileStore - // MXFileStore/userID/MXFileStore/Messages/ - // MXFileStore/userID/MXFileStore/Tokens/ - // MXFileStore/userID/MXFileStore/States/ - // MXFileStore/userID/MXFileStore/Summaries/ - // MXFileStore/userID/MXFileStore/receipt//receipts - // MXFileStore/userID/MXFileStore/accountData/ - // MXFileStore/userID/MXFileStore/users/ - // MXFileStore/userID/MXFileStore/groups/ - - // create the dirtree - mStoreFolderFile = new File(new File(mContext.getApplicationContext().getFilesDir(), MXFILE_STORE_FOLDER), userId); - - if (!mStoreFolderFile.exists()) { - mStoreFolderFile.mkdirs(); - } - - mGzStoreRoomsMessagesFolderFile = new File(mStoreFolderFile, MXFILE_STORE_GZ_ROOMS_MESSAGES_FOLDER); - if (!mGzStoreRoomsMessagesFolderFile.exists()) { - mGzStoreRoomsMessagesFolderFile.mkdirs(); - } - - mStoreRoomsTokensFolderFile = new File(mStoreFolderFile, MXFILE_STORE_ROOMS_TOKENS_FOLDER); - if (!mStoreRoomsTokensFolderFile.exists()) { - mStoreRoomsTokensFolderFile.mkdirs(); - } - - mGzStoreRoomsStateFolderFile = new File(mStoreFolderFile, MXFILE_STORE_GZ_ROOMS_STATE_FOLDER); - if (!mGzStoreRoomsStateFolderFile.exists()) { - mGzStoreRoomsStateFolderFile.mkdirs(); - } - - mGzStoreRoomsStateEventsFolderFile = new File(mStoreFolderFile, MXFILE_STORE_GZ_ROOMS_STATE_EVENTS_FOLDER); - if (!mGzStoreRoomsStateEventsFolderFile.exists()) { - mGzStoreRoomsStateEventsFolderFile.mkdirs(); - } - - mStoreRoomsSummaryFolderFile = new File(mStoreFolderFile, MXFILE_STORE_ROOMS_SUMMARY_FOLDER); - if (!mStoreRoomsSummaryFolderFile.exists()) { - mStoreRoomsSummaryFolderFile.mkdirs(); - } - - mStoreRoomsMessagesReceiptsFolderFile = new File(mStoreFolderFile, MXFILE_STORE_ROOMS_RECEIPT_FOLDER); - if (!mStoreRoomsMessagesReceiptsFolderFile.exists()) { - mStoreRoomsMessagesReceiptsFolderFile.mkdirs(); - } - - mStoreRoomsAccountDataFolderFile = new File(mStoreFolderFile, MXFILE_STORE_ROOMS_ACCOUNT_DATA_FOLDER); - if (!mStoreRoomsAccountDataFolderFile.exists()) { - mStoreRoomsAccountDataFolderFile.mkdirs(); - } - - mStoreUserFolderFile = new File(mStoreFolderFile, MXFILE_STORE_USER_FOLDER); - if (!mStoreUserFolderFile.exists()) { - mStoreUserFolderFile.mkdirs(); - } - - mStoreGroupsFolderFile = new File(mStoreFolderFile, MXFILE_STORE_GROUPS_FOLDER); - if (!mStoreGroupsFolderFile.exists()) { - mStoreGroupsFolderFile.mkdirs(); - } - } - - /** - * Constructor - * - * @param credentials the expected getCredentials - * @param enableFileEncryption set to true to enable file encryption. - * @param context the context. - */ - public MXFileStore(Credentials credentials, boolean enableFileEncryption, Context context) { - setContext(context); - - mEnableFileEncryption = enableFileEncryption; - - mIsReady = false; - mCredentials = credentials; - - mHandlerThread = new HandlerThread("MXFileStoreBackgroundThread_" + mCredentials.getUserId(), Thread.MIN_PRIORITY); - - createDirTree(mCredentials.getUserId()); - - // updated data - mRoomsToCommitForMessages = new HashSet<>(); - mRoomsToCommitForStates = new HashSet<>(); - //mRoomsToCommitForStatesEvents = new HashSet<>(); - mRoomsToCommitForSummaries = new HashSet<>(); - mRoomsToCommitForAccountData = new HashSet<>(); - mRoomsToCommitForReceipts = new HashSet<>(); - mUserIdsToCommit = new HashSet<>(); - mGroupsToCommit = new HashSet<>(); - - // check if the metadata file exists and if it is valid - loadMetaData(); - - if (null == mMetadata) { - deleteAllData(true); - } - - // create the metadata file if it does not exist - // either there is no store - // or the store was not properly initialised (the application crashed during the initialsync) - if ((null == mMetadata) || (null == mMetadata.mAccessToken)) { - mIsNewStorage = true; - mIsOpening = true; - mHandlerThread.start(); - mFileStoreHandler = new MXOsHandler(mHandlerThread.getLooper()); - - mMetadata = new MXFileStoreMetaData(); - mMetadata.mUserId = mCredentials.getUserId(); - mMetadata.mAccessToken = mCredentials.getAccessToken(); - mMetadata.mVersion = MXFILE_VERSION; - mMetaDataHasChanged = true; - saveMetaData(); - - mEventStreamToken = null; - - mIsOpening = false; - // nothing to load so ready to work - mIsReady = true; - mAreReceiptsReady = true; - } - } - - /** - * Killed the background thread. - * - * @param isKilled killed status - */ - private void setIsKilled(boolean isKilled) { - synchronized (this) { - mIsKilled = isKilled; - } - } - - /** - * @return true if the background thread is killed. - */ - private boolean isKilled() { - boolean isKilled; - - synchronized (this) { - isKilled = mIsKilled; - } - - return isKilled; - } - - /** - * Save changes in the store. - * If the store uses permanent storage like database or file, it is the optimised time - * to commit the last changes. - */ - @Override - public void commit() { - // Save data only if metaData exists - if ((null != mMetadata) && (null != mMetadata.mAccessToken) && !isKilled()) { - Log.d(LOG_TAG, "++ Commit"); - saveUsers(); - saveGroups(); - saveRoomsMessages(); - saveRoomStates(); - saveRoomStatesEvents(); - saveSummaries(); - saveRoomsAccountData(); - saveReceipts(); - saveMetaData(); - Log.d(LOG_TAG, "-- Commit"); - } - } - - /** - * Open the store. - */ - @Override - public void open() { - super.open(); - final long fLoadTimeT0 = System.currentTimeMillis(); - - // avoid concurrency call. - synchronized (this) { - if (!mIsReady && !mIsOpening && (null != mMetadata) && (null != mHandlerThread)) { - mIsOpening = true; - - Log.e(LOG_TAG, "Open the store."); - - // creation the background handler. - if (null == mFileStoreHandler) { - // avoid already started exception - // never succeeded to reproduce but it was reported in GA. - try { - mHandlerThread.start(); - } catch (IllegalThreadStateException e) { - Log.e(LOG_TAG, "mHandlerThread is already started.", e); - // already started - return; - } - mFileStoreHandler = new MXOsHandler(mHandlerThread.getLooper()); - } - - Runnable r = new Runnable() { - @Override - public void run() { - mFileStoreHandler.post(new Runnable() { - public void run() { - Log.e(LOG_TAG, "Open the store in the background thread."); - - String errorDescription = null; - boolean succeed = (mMetadata.mVersion == MXFILE_VERSION) - && TextUtils.equals(mMetadata.mUserId, mCredentials.getUserId()) - && TextUtils.equals(mMetadata.mAccessToken, mCredentials.getAccessToken()); - - if (!succeed) { - errorDescription = "Invalid store content"; - Log.e(LOG_TAG, errorDescription); - } - - if (succeed) { - succeed &= loadRoomsMessages(); - if (!succeed) { - errorDescription = "loadRoomsMessages fails"; - Log.e(LOG_TAG, errorDescription); - } else { - Log.d(LOG_TAG, "loadRoomsMessages succeeds"); - } - } - - if (succeed) { - succeed &= loadGroups(); - if (!succeed) { - errorDescription = "loadGroups fails"; - Log.e(LOG_TAG, errorDescription); - } else { - Log.d(LOG_TAG, "loadGroups succeeds"); - } - } - - if (succeed) { - succeed &= loadRoomsState(); - - if (!succeed) { - errorDescription = "loadRoomsState fails"; - Log.e(LOG_TAG, errorDescription); - } else { - Log.d(LOG_TAG, "loadRoomsState succeeds"); - long t0 = System.currentTimeMillis(); - Log.d(LOG_TAG, "Retrieve the users from the roomstate"); - - Collection rooms = getRooms(); - - for (Room room : rooms) { - Collection members = room.getState().getLoadedMembers(); - for (RoomMember member : members) { - updateUserWithRoomMemberEvent(member); - } - } - - long delta = System.currentTimeMillis() - t0; - Log.d(LOG_TAG, "Retrieve " + mUsers.size() + " users with the room states in " + delta + " ms"); - mStoreStats.put("Retrieve users", delta); - } - } - - if (succeed) { - succeed &= loadSummaries(); - - if (!succeed) { - errorDescription = "loadSummaries fails"; - Log.e(LOG_TAG, errorDescription); - } else { - Log.d(LOG_TAG, "loadSummaries succeeds"); - - // Check if the room summaries match to existing rooms. - // We could have more rooms than summaries because - // some of them are hidden. - // For example, the conference calls create a dummy room to manage - // the call events. - // check also if the user is a member of the room - // https://github.com/vector-im/riot-android/issues/1302 - - for (String roomId : mRoomSummaries.keySet()) { - Room room = getRoom(roomId); - - if (null == room) { - succeed = false; - Log.e(LOG_TAG, "loadSummaries : the room " + roomId + " does not exist"); - } else if (null == room.getMember(mCredentials.getUserId())) { - //succeed = false; - Log.e(LOG_TAG, "loadSummaries) : a summary exists for the roomId " - + roomId + " but the user is not anymore a member"); - } - } - } - } - - if (succeed) { - succeed &= loadRoomsAccountData(); - - if (!succeed) { - errorDescription = "loadRoomsAccountData fails"; - Log.e(LOG_TAG, errorDescription); - } else { - Log.d(LOG_TAG, "loadRoomsAccountData succeeds"); - } - } - - // do not expect having empty list - // assume that something is corrupted - if (!succeed) { - Log.e(LOG_TAG, "Fail to open the store in background"); - - // delete all data set mMetadata to null - // backup it to restore it - // the behaviour should be the same as first login - MXFileStoreMetaData tmpMetadata = mMetadata; - - deleteAllData(true); - - mRoomsToCommitForMessages = new HashSet<>(); - mRoomsToCommitForStates = new HashSet<>(); - //mRoomsToCommitForStatesEvents = new HashSet<>(); - mRoomsToCommitForSummaries = new HashSet<>(); - mRoomsToCommitForReceipts = new HashSet<>(); - - mMetadata = tmpMetadata; - - // reported by GA - // i don't see which path could have triggered this issue - // mMetadata should only be null at file store loading - if (null == mMetadata) { - mMetadata = new MXFileStoreMetaData(); - mMetadata.mUserId = mCredentials.getUserId(); - mMetadata.mAccessToken = mCredentials.getAccessToken(); - mMetaDataHasChanged = true; - } else { - mMetadata.mEventStreamToken = null; - } - mMetadata.mVersion = MXFILE_VERSION; - - // the event stream token is put to zero to ensure ta - mEventStreamToken = null; - mAreReceiptsReady = true; - } else { - Log.d(LOG_TAG, "++ store stats"); - Set roomIds = mRoomEvents.keySet(); - - for (String roomId : roomIds) { - Room room = getRoom(roomId); - - if ((null != room) && (null != room.getState())) { - int membersCount = room.getState().getLoadedMembers().size(); - int eventsCount = mRoomEvents.get(roomId).size(); - - Log.d(LOG_TAG, " room " + roomId - + " : (lazy loaded) membersCount " + membersCount - + " - eventsCount " + eventsCount); - } - } - - Log.d(LOG_TAG, "-- store stats"); - } - - // post processing - Log.d(LOG_TAG, "## open() : post processing."); - dispatchPostProcess(mCredentials.getUserId()); - mIsPostProcessingDone = true; - - synchronized (this) { - mIsReady = true; - } - mIsOpening = false; - - if (!succeed && !mIsNewStorage) { - Log.e(LOG_TAG, "The store is corrupted."); - dispatchOnStoreCorrupted(mCredentials.getUserId(), errorDescription); - } else { - // extract the room states - mRoomReceiptsToLoad.addAll(listFiles(mStoreRoomsMessagesReceiptsFolderFile.list())); - mPreloadTime = System.currentTimeMillis() - fLoadTimeT0; - if (mMetricsListener != null) { - mMetricsListener.onStorePreloaded(mPreloadTime); - } - - Log.d(LOG_TAG, "The store is opened."); - dispatchOnStoreReady(mCredentials.getUserId()); - - // load the following items with delay - // theses items are not required to be ready - - // load the receipts - loadReceipts(); - - // load the users - loadUsers(); - } - } - }); - } - }; - - Thread t = new Thread(r); - t.start(); - } else if (mIsReady) { - Runnable r = new Runnable() { - @Override - public void run() { - mFileStoreHandler.post(new Runnable() { - @Override - public void run() { - // should never happen - if (!mIsPostProcessingDone && !mIsNewStorage) { - Log.e(LOG_TAG, "## open() : is ready but the post processing was not yet done : please wait...."); - return; - } else { - if (!mIsPostProcessingDone) { - Log.e(LOG_TAG, "## open() : is ready but the post processing was not yet done."); - dispatchPostProcess(mCredentials.getUserId()); - mIsPostProcessingDone = true; - } else { - Log.e(LOG_TAG, "## open() when ready : the post processing is already done."); - } - dispatchOnStoreReady(mCredentials.getUserId()); - mPreloadTime = System.currentTimeMillis() - fLoadTimeT0; - if (mMetricsListener != null) { - mMetricsListener.onStorePreloaded(mPreloadTime); - } - } - } - }); - } - }; - - Thread t = new Thread(r); - t.start(); - } - - } - } - - /** - * Check if the read receipts are ready to be used. - * - * @return true if they are ready. - */ - @Override - public boolean areReceiptsReady() { - boolean res; - - synchronized (this) { - res = mAreReceiptsReady; - } - - return res; - } - - /** - * Provides the store preload time in milliseconds. - * - * @return the store preload time in milliseconds. - */ - @Override - public long getPreloadTime() { - return mPreloadTime; - } - - /** - * Provides some store stats - * - * @return the store stats - */ - public Map getStats() { - return mStoreStats; - } - - /** - * Close the store. - * Any pending operation must be complete in this call. - */ - @Override - public void close() { - Log.d(LOG_TAG, "Close the store"); - - super.close(); - setIsKilled(true); - if (null != mHandlerThread) { - mHandlerThread.quit(); - } - mHandlerThread = null; - } - - /** - * Clear the store. - * Any pending operation must be complete in this call. - */ - @Override - public void clear() { - Log.d(LOG_TAG, "Clear the store"); - super.clear(); - deleteAllData(false); - } - - /** - * Clear the filesystem storage. - * - * @param init true to init the filesystem dirtree - */ - private void deleteAllData(boolean init) { - // delete the dedicated directories - try { - ContentUtils.deleteDirectory(mStoreFolderFile); - if (init) { - createDirTree(mCredentials.getUserId()); - } - } catch (Exception e) { - Log.e(LOG_TAG, "deleteAllData failed " + e.getMessage(), e); - } - - if (init) { - initCommon(); - } - mMetadata = null; - mEventStreamToken = null; - mAreUsersLoaded = true; - } - - /** - * Indicate if the MXStore implementation stores data permanently. - * Permanent storage allows the SDK to make less requests at the startup. - * - * @return true if permanent. - */ - @Override - public boolean isPermanent() { - return true; - } - - /** - * Check if the initial load is performed. - * - * @return true if it is ready. - */ - @Override - public boolean isReady() { - synchronized (this) { - return mIsReady; - } - } - - /** - * @return true if the store is corrupted. - */ - @Override - public boolean isCorrupted() { - return false; - } - - /** - * Delete a directory with its content - * - * @param directory the base directory - * @return the cache file size - */ - private long directorySize(File directory) { - long directorySize = 0; - - if (directory.exists()) { - File[] files = directory.listFiles(); - - if (null != files) { - for (int i = 0; i < files.length; i++) { - if (files[i].isDirectory()) { - directorySize += directorySize(files[i]); - } else { - directorySize += files[i].length(); - } - } - } - } - - return directorySize; - } - - /** - * Returns to disk usage size in bytes. - * - * @return disk usage size - */ - @Override - public long diskUsage() { - return directorySize(mStoreFolderFile); - } - - /** - * Set the event stream token. - * - * @param token the event stream token - */ - @Override - public void setEventStreamToken(String token) { - Log.d(LOG_TAG, "Set token to " + token); - super.setEventStreamToken(token); - mMetaDataHasChanged = true; - } - - @Override - public boolean setDisplayName(String displayName, long ts) { - return mMetaDataHasChanged = super.setDisplayName(displayName, ts); - } - - @Override - public boolean setAvatarURL(String avatarURL, long ts) { - return mMetaDataHasChanged = super.setAvatarURL(avatarURL, ts); - } - - @Override - public void setThirdPartyIdentifiers(List identifiers) { - // privacy - //Log.d(LOG_TAG, "Set setThirdPartyIdentifiers to " + identifiers); - Log.d(LOG_TAG, "Set setThirdPartyIdentifiers"); - mMetaDataHasChanged = true; - super.setThirdPartyIdentifiers(identifiers); - } - - @Override - public void setIgnoredUserIdsList(List users) { - Log.d(LOG_TAG, "## setIgnoredUsers() : " + users); - mMetaDataHasChanged = true; - super.setIgnoredUserIdsList(users); - } - - @Override - public void setDirectChatRoomsDict(Map> directChatRoomsDict) { - Log.d(LOG_TAG, "## setDirectChatRoomsDict()"); - mMetaDataHasChanged = true; - super.setDirectChatRoomsDict(directChatRoomsDict); - } - - @Override - public void storeUser(User user) { - if (!TextUtils.equals(mCredentials.getUserId(), user.user_id)) { - mUserIdsToCommit.add(user.user_id); - } - super.storeUser(user); - } - - @Override - public void flushRoomEvents(String roomId) { - super.flushRoomEvents(roomId); - - mRoomsToCommitForMessages.add(roomId); - - if ((null != mMetadata) && (null != mMetadata.mAccessToken) && !isKilled()) { - saveRoomsMessages(); - } - } - - @Override - public void storeRoomEvents(String roomId, TokensChunkEvents tokensChunkEvents, EventTimeline.Direction direction) { - boolean canStore = true; - - // do not flush the room messages file - // when the user reads the room history and the events list size reaches its max size. - if (direction == EventTimeline.Direction.BACKWARDS) { - LinkedHashMap events = mRoomEvents.get(roomId); - - if (null != events) { - canStore = (events.size() < MAX_STORED_MESSAGES_COUNT); - - if (!canStore) { - Log.d(LOG_TAG, "storeRoomEvents : do not flush because reaching the max size"); - } - } - } - - super.storeRoomEvents(roomId, tokensChunkEvents, direction); - - if (canStore) { - mRoomsToCommitForMessages.add(roomId); - } - } - - /** - * Store a live room event. - * - * @param event The event to be stored. - */ - @Override - public void storeLiveRoomEvent(Event event) { - super.storeLiveRoomEvent(event); - mRoomsToCommitForMessages.add(event.roomId); - } - - @Override - public void deleteEvent(Event event) { - super.deleteEvent(event); - mRoomsToCommitForMessages.add(event.roomId); - } - - /** - * Delete the room messages and token files. - * - * @param roomId the room id. - */ - private void deleteRoomMessagesFiles(String roomId) { - // messages list - File messagesListFile = new File(mGzStoreRoomsMessagesFolderFile, roomId); - - // remove the files - if (messagesListFile.exists()) { - try { - messagesListFile.delete(); - } catch (Exception e) { - Log.e(LOG_TAG, "deleteRoomMessagesFiles - messagesListFile failed " + e.getMessage(), e); - } - } - - File tokenFile = new File(mStoreRoomsTokensFolderFile, roomId); - if (tokenFile.exists()) { - try { - tokenFile.delete(); - } catch (Exception e) { - Log.e(LOG_TAG, "deleteRoomMessagesFiles - tokenFile failed " + e.getMessage(), e); - } - } - } - - @Override - public void deleteRoom(String roomId) { - Log.d(LOG_TAG, "deleteRoom " + roomId); - - super.deleteRoom(roomId); - deleteRoomMessagesFiles(roomId); - deleteRoomStateFile(roomId); - deleteRoomSummaryFile(roomId); - deleteRoomReceiptsFile(roomId); - deleteRoomAccountDataFile(roomId); - } - - @Override - public void deleteAllRoomMessages(String roomId, boolean keepUnsent) { - Log.d(LOG_TAG, "deleteAllRoomMessages " + roomId); - - super.deleteAllRoomMessages(roomId, keepUnsent); - if (!keepUnsent) { - deleteRoomMessagesFiles(roomId); - } - - deleteRoomSummaryFile(roomId); - - mRoomsToCommitForMessages.add(roomId); - mRoomsToCommitForSummaries.add(roomId); - } - - @Override - public void storeLiveStateForRoom(String roomId) { - super.storeLiveStateForRoom(roomId); - mRoomsToCommitForStates.add(roomId); - } - - //================================================================================ - // Summary management - //================================================================================ - - @Override - public void flushSummary(RoomSummary summary) { - super.flushSummary(summary); - mRoomsToCommitForSummaries.add(summary.getRoomId()); - - if ((null != mMetadata) && (null != mMetadata.mAccessToken) && !isKilled()) { - saveSummaries(); - } - } - - @Override - public void flushSummaries() { - super.flushSummaries(); - - // add any existing roomid to the list to save all - mRoomsToCommitForSummaries.addAll(mRoomSummaries.keySet()); - - if ((null != mMetadata) && (null != mMetadata.mAccessToken) && !isKilled()) { - saveSummaries(); - } - } - - @Override - public void storeSummary(RoomSummary summary) { - super.storeSummary(summary); - - if ((null != summary) && (null != summary.getRoomId()) && !mRoomsToCommitForSummaries.contains(summary.getRoomId())) { - mRoomsToCommitForSummaries.add(summary.getRoomId()); - } - } - - //================================================================================ - // users management - //================================================================================ - - /** - * Flush users list - */ - private void saveUsers() { - if (!mAreUsersLoaded) { - // please wait - return; - } - - // some updated rooms ? - if ((mUserIdsToCommit.size() > 0) && (null != mFileStoreHandler)) { - // get the list - final Set fUserIds = mUserIdsToCommit; - mUserIdsToCommit = new HashSet<>(); - - try { - final Set fUsers; - - synchronized (mUsers) { - fUsers = new HashSet<>(mUsers.values()); - } - - Runnable r = new Runnable() { - @Override - public void run() { - mFileStoreHandler.post(new Runnable() { - public void run() { - if (!isKilled()) { - Log.d(LOG_TAG, "saveUsers " + fUserIds.size() + " users (" + fUsers.size() + " known ones)"); - - long start = System.currentTimeMillis(); - - // the users are split into groups to save time - Map> usersGroups = new HashMap<>(); - - // finds the group for each updated user - for (String userId : fUserIds) { - User user; - - synchronized (mUsers) { - user = mUsers.get(userId); - } - - if (null != user) { - int hashCode = user.getStorageHashKey(); - - if (!usersGroups.containsKey(hashCode)) { - usersGroups.put(hashCode, new ArrayList()); - } - } - } - - // gather the user to the dedicated group if they need to be updated - for (User user : fUsers) { - if (usersGroups.containsKey(user.getStorageHashKey())) { - usersGroups.get(user.getStorageHashKey()).add(user); - } - } - - // save the groups - for (int hashKey : usersGroups.keySet()) { - writeObject("saveUser " + hashKey, new File(mStoreUserFolderFile, hashKey + ""), usersGroups.get(hashKey)); - } - - Log.d(LOG_TAG, "saveUsers done in " + (System.currentTimeMillis() - start) + " ms"); - } - } - }); - } - }; - - Thread t = new Thread(r); - t.start(); - } catch (OutOfMemoryError oom) { - Log.e(LOG_TAG, "saveUser : cannot clone the users list" + oom.getMessage(), oom); - } - } - } - - /** - * Load the user information from the filesystem.. - */ - private void loadUsers() { - List filenames = listFiles(mStoreUserFolderFile.list()); - long start = System.currentTimeMillis(); - - List users = new ArrayList<>(); - - // list the files - for (String filename : filenames) { - File messagesListFile = new File(mStoreUserFolderFile, filename); - Object usersAsVoid = readObject("loadUsers " + filename, messagesListFile); - - if (null != usersAsVoid) { - try { - users.addAll((List) usersAsVoid); - } catch (Exception e) { - Log.e(LOG_TAG, "loadUsers failed : " + e.toString(), e); - } - } - } - - // update the hash map - for (User user : users) { - synchronized (mUsers) { - User currentUser = mUsers.get(user.user_id); - - if ((null == currentUser) || // not defined - currentUser.isRetrievedFromRoomMember() || // tmp user until retrieved it - (currentUser.getLatestPresenceTs() < user.getLatestPresenceTs())) // newer presence - { - mUsers.put(user.user_id, user); - } - } - } - - long delta = (System.currentTimeMillis() - start); - Log.e(LOG_TAG, "loadUsers (" + filenames.size() + " files) : retrieve " + mUsers.size() + " users in " + delta + "ms"); - mStoreStats.put("loadUsers", delta); - - mAreUsersLoaded = true; - - // save any pending save - saveUsers(); - } - - //================================================================================ - // Room messages management - //================================================================================ - - /** - * Computes the saved events map to reduce storage footprint. - * - * @param roomId the room id - * @return the saved eventMap - */ - private LinkedHashMap getSavedEventsMap(String roomId) { - LinkedHashMap eventsMap; - - synchronized (mRoomEventsLock) { - eventsMap = mRoomEvents.get(roomId); - } - - List eventsList; - - synchronized (mRoomEventsLock) { - eventsList = new ArrayList<>(eventsMap.values()); - } - - int startIndex = 0; - - // try to reduce the number of stored messages - // it does not make sense to keep the full history. - - // the method consists in saving messages until finding the oldest known token. - // At initial sync, it is not saved so keep the whole history. - // if the user back paginates, the token is stored in the event. - // if some messages are received, the token is stored in the event. - if (eventsList.size() > MAX_STORED_MESSAGES_COUNT) { - // search backward the first known token - for (startIndex = eventsList.size() - MAX_STORED_MESSAGES_COUNT; !eventsList.get(startIndex).hasToken() && (startIndex > 0); startIndex--) - ; - - if (startIndex > 0) { - Log.d(LOG_TAG, "## getSavedEveventsMap() : " + roomId + " reduce the number of messages " + eventsList.size() - + " -> " + (eventsList.size() - startIndex)); - } - } - - LinkedHashMap savedEvents = new LinkedHashMap<>(); - - for (int index = startIndex; index < eventsList.size(); index++) { - Event event = eventsList.get(index); - savedEvents.put(event.eventId, event); - } - - return savedEvents; - } - - private void saveRoomMessages(String roomId) { - LinkedHashMap eventsHash; - synchronized (mRoomEventsLock) { - eventsHash = mRoomEvents.get(roomId); - } - - String token = mRoomTokens.get(roomId); - - // the list exists ? - if ((null != eventsHash) && (null != token)) { - long t0 = System.currentTimeMillis(); - - LinkedHashMap savedEventsMap = getSavedEventsMap(roomId); - - if (!writeObject("saveRoomsMessage " + roomId, new File(mGzStoreRoomsMessagesFolderFile, roomId), savedEventsMap)) { - return; - } - - if (!writeObject("saveRoomsMessage " + roomId, new File(mStoreRoomsTokensFolderFile, roomId), token)) { - return; - } - - Log.d(LOG_TAG, "saveRoomsMessage (" + roomId + ") : " + savedEventsMap.size() + " messages saved in " + (System.currentTimeMillis() - t0) + " ms"); - } else { - deleteRoomMessagesFiles(roomId); - } - } - - /** - * Flush updates rooms messages list files. - */ - private void saveRoomsMessages() { - // some updated rooms ? - if ((mRoomsToCommitForMessages.size() > 0) && (null != mFileStoreHandler)) { - // get the list - final Set fRoomsToCommitForMessages = mRoomsToCommitForMessages; - mRoomsToCommitForMessages = new HashSet<>(); - - Runnable r = new Runnable() { - @Override - public void run() { - mFileStoreHandler.post(new Runnable() { - public void run() { - if (!isKilled()) { - long start = System.currentTimeMillis(); - - for (String roomId : fRoomsToCommitForMessages) { - saveRoomMessages(roomId); - } - - Log.d(LOG_TAG, "saveRoomsMessages : " + fRoomsToCommitForMessages.size() + " rooms in " - + (System.currentTimeMillis() - start) + " ms"); - } - } - }); - } - }; - - Thread t = new Thread(r); - t.start(); - } - } - - /** - * Load room messages from the filesystem. - * - * @param roomId the room id. - * @return true if succeed. - */ - private boolean loadRoomMessages(final String roomId) { - boolean succeeded = true; - boolean shouldSave = false; - LinkedHashMap events = null; - - File messagesListFile = new File(mGzStoreRoomsMessagesFolderFile, roomId); - - if (messagesListFile.exists()) { - Object eventsAsVoid = readObject("events " + roomId, messagesListFile); - - if (null != eventsAsVoid) { - try { - events = (LinkedHashMap) eventsAsVoid; - } catch (Exception e) { - Log.e(LOG_TAG, "loadRoomMessages " + roomId + "failed : " + e.getMessage(), e); - return false; - } - - if (events.size() > (2 * MAX_STORED_MESSAGES_COUNT)) { - Log.d(LOG_TAG, "## loadRoomMessages() : the room " + roomId + " has " + events.size() - + " stored events : we need to find a way to reduce it."); - } - - // finalizes the deserialization - for (Event event : events.values()) { - // if a message was not sent, mark it as UNDELIVERED - if ((event.mSentState == Event.SentState.UNSENT) - || (event.mSentState == Event.SentState.SENDING) - || (event.mSentState == Event.SentState.WAITING_RETRY) - || (event.mSentState == Event.SentState.ENCRYPTING)) { - event.mSentState = Event.SentState.UNDELIVERED; - shouldSave = true; - } - } - } else { - return false; - } - } - - // succeeds to extract the message list - if (null != events) { - // create the room object - final Room room = new Room(getDataHandler(), this, roomId); - // do not wait that the live state update - room.setReadyState(true); - storeRoom(room); - - mRoomEvents.put(roomId, events); - } - - if (shouldSave) { - saveRoomMessages(roomId); - } - - return succeeded; - } - - /** - * Load the room token from the file system. - * - * @param roomId the room id. - * @return true if it succeeds. - */ - private boolean loadRoomToken(final String roomId) { - boolean succeed = true; - - Room room = getRoom(roomId); - - // should always be true - if (null != room) { - String token = null; - - try { - File messagesListFile = new File(mStoreRoomsTokensFolderFile, roomId); - Object tokenAsVoid = readObject("loadRoomToken " + roomId, messagesListFile); - - if (null == tokenAsVoid) { - succeed = false; - } else { - token = (String) tokenAsVoid; - - // check if the oldest event has a token. - LinkedHashMap eventsHash = mRoomEvents.get(roomId); - if ((null != eventsHash) && (eventsHash.size() > 0)) { - Event event = eventsHash.values().iterator().next(); - - // the room history could have been reduced to save memory - // so, if the oldest messages has a token, use it instead of the stored token. - if (null != event.mToken) { - token = event.mToken; - } - } - } - } catch (Exception e) { - succeed = false; - Log.e(LOG_TAG, "loadRoomToken failed : " + e.toString(), e); - } - - if (null != token) { - mRoomTokens.put(roomId, token); - } else { - deleteRoom(roomId); - } - } else { - try { - File messagesListFile = new File(mStoreRoomsTokensFolderFile, roomId); - messagesListFile.delete(); - } catch (Exception e) { - Log.e(LOG_TAG, "loadRoomToken failed with error " + e.getMessage(), e); - } - } - - return succeed; - } - - /** - * Load room messages from the filesystem. - * - * @return true if the operation succeeds. - */ - private boolean loadRoomsMessages() { - boolean succeed = true; - - try { - // extract the messages list - List filenames = listFiles(mGzStoreRoomsMessagesFolderFile.list()); - - long start = System.currentTimeMillis(); - - for (String filename : filenames) { - if (succeed) { - succeed &= loadRoomMessages(filename); - } - } - - if (succeed) { - long delta = (System.currentTimeMillis() - start); - Log.d(LOG_TAG, "loadRoomMessages : " + filenames.size() + " rooms in " + delta + " ms"); - mStoreStats.put("loadRoomMessages", delta); - } - - // extract the tokens list - filenames = listFiles(mStoreRoomsTokensFolderFile.list()); - - start = System.currentTimeMillis(); - - for (String filename : filenames) { - if (succeed) { - succeed &= loadRoomToken(filename); - } - } - - if (succeed) { - Log.d(LOG_TAG, "loadRoomToken : " + filenames.size() + " rooms in " + (System.currentTimeMillis() - start) + " ms"); - } - - } catch (Exception e) { - succeed = false; - Log.e(LOG_TAG, "loadRoomToken failed : " + e.getMessage(), e); - } - - return succeed; - } - - //================================================================================ - // Room states management - //================================================================================ - - // waiting that the rooms state events are loaded - private Map> mPendingRoomStateEvents = new HashMap<>(); - - @Override - public void storeRoomStateEvent(final String roomId, final im.vector.matrix.android.api.session.events.model.Event event) { - /*boolean isAlreadyLoaded = true; - - synchronized (mRoomStateEventsByRoomId) { - isAlreadyLoaded = mRoomStateEventsByRoomId.containsKey(roomId); - } - - if (isAlreadyLoaded) { - super.storeRoomStateEvent(roomId, event); - mRoomsToCommitForStatesEvents.add(roomId); - return; - } - - boolean isRequestPending = false; - - synchronized (mPendingRoomStateEvents) { - // a loading is already in progress - if (mPendingRoomStateEvents.containsKey(roomId)) { - mPendingRoomStateEvents.get(roomId).add(event); - isRequestPending = true; - } - } - - if (isRequestPending) { - return; - } - - synchronized (mPendingRoomStateEvents) { - List events = new ArrayList(); - events.add(event); - mPendingRoomStateEvents.put(roomId, events); - } - - getRoomStateEvents(roomId, new SimpleApiCallback>() { - @Override - public void onSuccess(List events) { - List pendingEvents; - - synchronized (mPendingRoomStateEvents) { - pendingEvents = mPendingRoomStateEvents.get(roomId); - mPendingRoomStateEvents.remove(roomId); - } - - // add them by now - for (Event event : pendingEvents) { - storeRoomStateEvent(roomId, event); - } - } - });*/ - } - - /** - * Save the room state. - * - * @param roomId the room id. - */ - private void saveRoomStateEvents(final String roomId) { - /*Log.d(LOG_TAG, "++ saveRoomStateEvents " + roomId); - - File roomStateFile = new File(mGzStoreRoomsStateEventsFolderFile, roomId); - Map eventsMap = mRoomStateEventsByRoomId.get(roomId); - - if (null != eventsMap) { - List events = new ArrayList<>(eventsMap.values()); - - long start1 = System.currentTimeMillis(); - writeObject("saveRoomStateEvents " + roomId, roomStateFile, events); - Log.d(LOG_TAG, "saveRoomStateEvents " + roomId + " :" + events.size() + " events : " + (System.currentTimeMillis() - start1) + " ms"); - } else { - Log.d(LOG_TAG, "-- saveRoomStateEvents " + roomId + " : empty list"); - }*/ - } - - /** - * Flush the room state events files. - */ - private void saveRoomStatesEvents() { - /*if ((mRoomsToCommitForStatesEvents.size() > 0) && (null != mFileStoreHandler)) { - // get the list - final Set fRoomsToCommitForStatesEvents = new HashSet<>(mRoomsToCommitForStatesEvents); - mRoomsToCommitForStatesEvents = new HashSet<>(); - - Runnable r = new Runnable() { - @Override - public void run() { - mFileStoreHandler.post(new Runnable() { - public void run() { - if (!isKilled()) { - long start = System.currentTimeMillis(); - - for (String roomId : fRoomsToCommitForStatesEvents) { - saveRoomStateEvents(roomId); - } - - Log.d(LOG_TAG, "saveRoomStatesEvents : " + fRoomsToCommitForStatesEvents.size() + " rooms in " - + (System.currentTimeMillis() - start) + " ms"); - } - } - }); - } - }; - - Thread t = new Thread(r); - t.start(); - }*/ - } - - @Override - public void getRoomStateEvents(final String roomId, final ApiCallback> callback) { - boolean isAlreadyLoaded = true; - - /*synchronized (mRoomStateEventsByRoomId) { - isAlreadyLoaded = mRoomStateEventsByRoomId.containsKey(roomId); - }*/ - - if (isAlreadyLoaded) { - super.getRoomStateEvents(roomId, callback); - return; - } - - /*Runnable r = new Runnable() { - @Override - public void run() { - mFileStoreHandler.post(new Runnable() { - public void run() { - if (!isKilled()) { - File statesEventsFile = new File(mGzStoreRoomsStateEventsFolderFile, roomId); - Map eventsMap = new HashMap<>(); - List eventsList = new ArrayList<>(); - - long start = System.currentTimeMillis(); - - if ((null != statesEventsFile) && statesEventsFile.exists()) { - try { - Object eventsListAsVoid = readObject("getRoomStateEvents", statesEventsFile); - - if (null != eventsListAsVoid) { - List events = (List) eventsListAsVoid; - - for (Event event : events) { - eventsMap.put(event.stateKey, event); - } - } - } catch (Exception e) { - Log.e(LOG_TAG, "getRoomStateEvents failed : " + e.getMessage(), e); - } - } - - synchronized (mRoomStateEventsByRoomId) { - mRoomStateEventsByRoomId.put(roomId, eventsMap); - } - - Log.d(LOG_TAG, "getRoomStateEvents : retrieve " + eventsList.size() + " events in " + (System.currentTimeMillis() - start) + " ms"); - callback.onSuccess(eventsList); - } - } - }); - } - }; - - Thread t = new Thread(r); - t.start();*/ - } - - /** - * Delete the room state file. - * - * @param roomId the room id. - */ - private void deleteRoomStateFile(String roomId) { - // states list - File statesFile = new File(mGzStoreRoomsStateFolderFile, roomId); - - if (statesFile.exists()) { - try { - statesFile.delete(); - } catch (Exception e) { - Log.e(LOG_TAG, "deleteRoomStateFile failed with error " + e.getMessage(), e); - } - } - - File statesEventsFile = new File(mGzStoreRoomsStateEventsFolderFile, roomId); - - if (statesEventsFile.exists()) { - try { - statesEventsFile.delete(); - } catch (Exception e) { - Log.e(LOG_TAG, "deleteRoomStateFile failed with error " + e.getMessage(), e); - } - } - } - - /** - * Save the room state. - * - * @param roomId the room id. - */ - private void saveRoomState(final String roomId) { - Log.d(LOG_TAG, "++ saveRoomsState " + roomId); - - File roomStateFile = new File(mGzStoreRoomsStateFolderFile, roomId); - Room room = mRooms.get(roomId); - - if (null != room) { - long start1 = System.currentTimeMillis(); - writeObject("saveRoomsState " + roomId, roomStateFile, room.getState()); - Log.d(LOG_TAG, "saveRoomsState " + room.getNumberOfMembers() + " members : " + (System.currentTimeMillis() - start1) + " ms"); - } else { - Log.d(LOG_TAG, "saveRoomsState : delete the room state"); - deleteRoomStateFile(roomId); - } - - Log.d(LOG_TAG, "-- saveRoomsState " + roomId); - } - - /** - * Flush the room state files. - */ - private void saveRoomStates() { - if ((mRoomsToCommitForStates.size() > 0) && (null != mFileStoreHandler)) { - // get the list - final Set fRoomsToCommitForStates = mRoomsToCommitForStates; - mRoomsToCommitForStates = new HashSet<>(); - - Runnable r = new Runnable() { - @Override - public void run() { - mFileStoreHandler.post(new Runnable() { - public void run() { - if (!isKilled()) { - long start = System.currentTimeMillis(); - - for (String roomId : fRoomsToCommitForStates) { - saveRoomState(roomId); - } - - Log.d(LOG_TAG, "saveRoomsState : " + fRoomsToCommitForStates.size() + " rooms in " - + (System.currentTimeMillis() - start) + " ms"); - } - } - }); - } - }; - - Thread t = new Thread(r); - t.start(); - } - } - - /** - * Load a room state from the file system. - * - * @param roomId the room id. - * @return true if the operation succeeds. - */ - private boolean loadRoomState(final String roomId) { - boolean succeed = true; - - Room room = getRoom(roomId); - - // should always be true - if (null != room) { - RoomState liveState = null; - - try { - // the room state is not zipped - File roomStateFile = new File(mGzStoreRoomsStateFolderFile, roomId); - - // new format - if (roomStateFile.exists()) { - Object roomStateAsObject = readObject("loadRoomState " + roomId, roomStateFile); - - if (null == roomStateAsObject) { - succeed = false; - } else { - liveState = (RoomState) roomStateAsObject; - } - } - } catch (Exception e) { - succeed = false; - Log.e(LOG_TAG, "loadRoomState failed : " + e.getMessage(), e); - } - - if (null != liveState) { - room.getTimeline().setState(liveState); - } else { - deleteRoom(roomId); - } - } else { - try { - File messagesListFile = new File(mGzStoreRoomsStateFolderFile, roomId); - messagesListFile.delete(); - - } catch (Exception e) { - Log.e(LOG_TAG, "loadRoomState failed to delete a file : " + e.getMessage(), e); - } - } - - return succeed; - } - - /** - * Load room state from the file system. - * - * @return true if the operation succeeds. - */ - private boolean loadRoomsState() { - boolean succeed = true; - - try { - long start = System.currentTimeMillis(); - - List filenames = listFiles(mGzStoreRoomsStateFolderFile.list()); - - for (String filename : filenames) { - if (succeed) { - succeed &= loadRoomState(filename); - } - } - - long delta = (System.currentTimeMillis() - start); - Log.d(LOG_TAG, "loadRoomsState " + filenames.size() + " rooms in " + delta + " ms"); - mStoreStats.put("loadRoomsState", delta); - - } catch (Exception e) { - succeed = false; - Log.e(LOG_TAG, "loadRoomsState failed : " + e.getMessage(), e); - } - - return succeed; - } - - //================================================================================ - // AccountData management - //================================================================================ - - /** - * Delete the room account data file. - * - * @param roomId the room id. - */ - private void deleteRoomAccountDataFile(String roomId) { - File file = new File(mStoreRoomsAccountDataFolderFile, roomId); - - // remove the files - if (file.exists()) { - try { - file.delete(); - } catch (Exception e) { - Log.e(LOG_TAG, "deleteRoomAccountDataFile failed : " + e.getMessage(), e); - } - } - } - - /** - * Flush the pending account data. - */ - private void saveRoomsAccountData() { - if ((mRoomsToCommitForAccountData.size() > 0) && (null != mFileStoreHandler)) { - // get the list - final Set fRoomsToCommitForAccountData = mRoomsToCommitForAccountData; - mRoomsToCommitForAccountData = new HashSet<>(); - - Runnable r = new Runnable() { - @Override - public void run() { - mFileStoreHandler.post(new Runnable() { - public void run() { - if (!isKilled()) { - long start = System.currentTimeMillis(); - - for (String roomId : fRoomsToCommitForAccountData) { - RoomAccountData accountData = mRoomAccountData.get(roomId); - - if (null != accountData) { - writeObject("saveRoomsAccountData " + roomId, new File(mStoreRoomsAccountDataFolderFile, roomId), accountData); - } else { - deleteRoomAccountDataFile(roomId); - } - } - - Log.d(LOG_TAG, "saveSummaries : " + fRoomsToCommitForAccountData.size() + " account data in " - + (System.currentTimeMillis() - start) + " ms"); - } - } - }); - } - }; - - Thread t = new Thread(r); - t.start(); - } - } - - /*** - * Load the account Data of a dedicated room. - * @param roomId the room Id - * @return true if the operation succeeds. - */ - private boolean loadRoomAccountData(final String roomId) { - boolean succeeded = true; - RoomAccountData roomAccountData = null; - - try { - File accountDataFile = new File(mStoreRoomsAccountDataFolderFile, roomId); - - if (accountDataFile.exists()) { - Object accountAsVoid = readObject("loadRoomAccountData " + roomId, accountDataFile); - - if (null == accountAsVoid) { - Log.e(LOG_TAG, "loadRoomAccountData failed"); - return false; - } - - roomAccountData = (RoomAccountData) accountAsVoid; - } - } catch (Exception e) { - succeeded = false; - Log.e(LOG_TAG, "loadRoomAccountData failed : " + e.toString(), e); - } - - // succeeds to extract the message list - if (null != roomAccountData) { - Room room = getRoom(roomId); - - if (null != room) { - room.setAccountData(roomAccountData); - } - } - - return succeeded; - } - - /** - * Load room accountData from the filesystem. - * - * @return true if the operation succeeds. - */ - private boolean loadRoomsAccountData() { - boolean succeed = true; - - try { - // extract the messages list - List filenames = listFiles(mStoreRoomsAccountDataFolderFile.list()); - - long start = System.currentTimeMillis(); - - for (String filename : filenames) { - succeed &= loadRoomAccountData(filename); - } - - if (succeed) { - Log.d(LOG_TAG, "loadRoomsAccountData : " + filenames.size() + " rooms in " + (System.currentTimeMillis() - start) + " ms"); - } - } catch (Exception e) { - succeed = false; - Log.e(LOG_TAG, "loadRoomsAccountData failed : " + e.getMessage(), e); - } - - return succeed; - } - - @Override - public void storeAccountData(String roomId, RoomAccountData accountData) { - super.storeAccountData(roomId, accountData); - - if (null != roomId) { - Room room = mRooms.get(roomId); - - // sanity checks - if ((room != null) && (null != accountData)) { - mRoomsToCommitForAccountData.add(roomId); - } - } - } - - //================================================================================ - // Summary management - //================================================================================ - - /** - * Delete the room summary file. - * - * @param roomId the room id. - */ - private void deleteRoomSummaryFile(String roomId) { - // states list - File statesFile = new File(mStoreRoomsSummaryFolderFile, roomId); - - // remove the files - if (statesFile.exists()) { - try { - statesFile.delete(); - } catch (Exception e) { - Log.e(LOG_TAG, "deleteRoomSummaryFile failed : " + e.getMessage(), e); - } - } - } - - /** - * Flush the pending summaries. - */ - private void saveSummaries() { - if ((mRoomsToCommitForSummaries.size() > 0) && (null != mFileStoreHandler)) { - // get the list - final Set fRoomsToCommitForSummaries = mRoomsToCommitForSummaries; - mRoomsToCommitForSummaries = new HashSet<>(); - - Runnable r = new Runnable() { - @Override - public void run() { - mFileStoreHandler.post(new Runnable() { - public void run() { - if (!isKilled()) { - long start = System.currentTimeMillis(); - - for (String roomId : fRoomsToCommitForSummaries) { - try { - File roomSummaryFile = new File(mStoreRoomsSummaryFolderFile, roomId); - RoomSummary roomSummary = mRoomSummaries.get(roomId); - - if (null != roomSummary) { - writeObject("saveSummaries " + roomId, roomSummaryFile, roomSummary); - } else { - deleteRoomSummaryFile(roomId); - } - } catch (OutOfMemoryError oom) { - dispatchOOM(oom); - } catch (Exception e) { - Log.e(LOG_TAG, "saveSummaries failed : " + e.getMessage(), e); - // Toast.makeText(mContext, "saveSummaries failed " + e.getLocalizedMessage(), Toast.LENGTH_LONG).show(); - } - } - - Log.d(LOG_TAG, "saveSummaries : " + fRoomsToCommitForSummaries.size() + " summaries in " - + (System.currentTimeMillis() - start) + " ms"); - } - } - }); - } - }; - - Thread t = new Thread(r); - t.start(); - } - } - - /** - * Load the room summary from the files system. - * - * @param roomId the room id. - * @return true if the operation succeeds; - */ - private boolean loadSummary(final String roomId) { - boolean succeed = true; - - // do not check if the room exists here. - // if the user is invited to a room, the room object is not created until it is joined. - RoomSummary summary = null; - - try { - File messagesListFile = new File(mStoreRoomsSummaryFolderFile, roomId); - Object summaryAsVoid = readObject("loadSummary " + roomId, messagesListFile); - - if (null == summaryAsVoid) { - Log.e(LOG_TAG, "loadSummary failed"); - return false; - } - - summary = (RoomSummary) summaryAsVoid; - } catch (Exception e) { - succeed = false; - Log.e(LOG_TAG, "loadSummary failed : " + e.getMessage(), e); - } - - if (null != summary) { - //summary.getLatestReceivedEvent().finalizeDeserialization(); - - Room room = getRoom(summary.getRoomId()); - - // the room state is not saved in the summary. - // it is restored from the room - if (null != room) { - summary.setLatestRoomState(room.getState()); - } - - mRoomSummaries.put(roomId, summary); - } - - return succeed; - } - - /** - * Load room summaries from the file system. - * - * @return true if the operation succeeds. - */ - private boolean loadSummaries() { - boolean succeed = true; - try { - // extract the room states - List filenames = listFiles(mStoreRoomsSummaryFolderFile.list()); - - long start = System.currentTimeMillis(); - - for (String filename : filenames) { - succeed &= loadSummary(filename); - } - - long delta = (System.currentTimeMillis() - start); - Log.d(LOG_TAG, "loadSummaries " + filenames.size() + " rooms in " + delta + " ms"); - mStoreStats.put("loadSummaries", delta); - } catch (Exception e) { - succeed = false; - Log.e(LOG_TAG, "loadSummaries failed : " + e.getMessage(), e); - } - - return succeed; - } - - //================================================================================ - // Metadata management - //================================================================================ - - /** - * Load the metadata info from the file system. - */ - private void loadMetaData() { - long start = System.currentTimeMillis(); - - // init members - mEventStreamToken = null; - mMetadata = null; - - File metaDataFile = new File(mStoreFolderFile, MXFILE_STORE_METADATA_FILE_NAME); - - if (metaDataFile.exists()) { - Object metadataAsVoid = readObject("loadMetaData", metaDataFile); - - if (null != metadataAsVoid) { - try { - mMetadata = (MXFileStoreMetaData) metadataAsVoid; - - // remove pending \n - if (null != mMetadata.mUserDisplayName) { - mMetadata.mUserDisplayName.trim(); - } - - // extract the latest event stream token - mEventStreamToken = mMetadata.mEventStreamToken; - } catch (Exception e) { - Log.e(LOG_TAG, "## loadMetaData() : is corrupted", e); - return; - } - } - } - - Log.d(LOG_TAG, "loadMetaData : " + (System.currentTimeMillis() - start) + " ms"); - } - - /** - * flush the metadata info from the file system. - */ - private void saveMetaData() { - if ((mMetaDataHasChanged) && (null != mFileStoreHandler) && (null != mMetadata)) { - mMetaDataHasChanged = false; - - final MXFileStoreMetaData fMetadata = mMetadata.deepCopy(); - - Runnable r = new Runnable() { - @Override - public void run() { - mFileStoreHandler.post(new Runnable() { - public void run() { - if (!mIsKilled) { - // save the metadata only when there is a current valid stream token - // avoid saving the metadata if the store has been cleared - if (null != mMetadata.mEventStreamToken) { - long start = System.currentTimeMillis(); - writeObject("saveMetaData", new File(mStoreFolderFile, MXFILE_STORE_METADATA_FILE_NAME), fMetadata); - Log.d(LOG_TAG, "saveMetaData : " + (System.currentTimeMillis() - start) + " ms"); - } else { - Log.e(LOG_TAG, "## saveMetaData() : cancelled because mEventStreamToken is null"); - } - } - } - }); - } - }; - - Thread t = new Thread(r); - t.start(); - } - } - - //================================================================================ - // Event receipts management - //================================================================================ - - @Override - public List getEventReceipts(String roomId, String eventId, boolean excludeSelf, boolean sort) { - synchronized (mRoomReceiptsToLoad) { - int pos = mRoomReceiptsToLoad.indexOf(roomId); - - // the user requires the receipts asap - if (pos >= 2) { - mRoomReceiptsToLoad.remove(roomId); - // index 0 is the current managed one - mRoomReceiptsToLoad.add(1, roomId); - } - } - - return super.getEventReceipts(roomId, eventId, excludeSelf, sort); - } - - /** - * Store the receipt for an user in a room - * - * @param receipt The event - * @param roomId The roomId - * @return true if the receipt has been stored - */ - @Override - public boolean storeReceipt(ReceiptData receipt, String roomId) { - boolean res = super.storeReceipt(receipt, roomId); - - if (res) { - synchronized (this) { - mRoomsToCommitForReceipts.add(roomId); - } - } - - return res; - } - - /*** - * Load the events receipts. - * @param roomId the room Id - * @return true if the operation succeeds. - */ - private boolean loadReceipts(String roomId) { - Map receiptsMap = null; - File file = new File(mStoreRoomsMessagesReceiptsFolderFile, roomId); - - if (file.exists()) { - Object receiptsAsVoid = readObject("loadReceipts " + roomId, file); - - if (null != receiptsAsVoid) { - try { - List receipts = (List) receiptsAsVoid; - - receiptsMap = new HashMap<>(); - - for (ReceiptData r : receipts) { - receiptsMap.put(r.userId, r); - } - } catch (Exception e) { - Log.e(LOG_TAG, "loadReceipts failed : " + e.getMessage(), e); - return false; - } - } else { - return false; - } - } - - if (null != receiptsMap) { - Map currentReceiptMap; - - synchronized (mReceiptsByRoomIdLock) { - currentReceiptMap = mReceiptsByRoomId.get(roomId); - mReceiptsByRoomId.put(roomId, receiptsMap); - } - - // merge the current read receipts - if (null != currentReceiptMap) { - Collection receipts = currentReceiptMap.values(); - - for (ReceiptData receipt : receipts) { - storeReceipt(receipt, roomId); - } - } - - dispatchOnReadReceiptsLoaded(roomId); - } - - return true; - } - - /** - * Load event receipts from the file system. - * - * @return true if the operation succeeds. - */ - private boolean loadReceipts() { - boolean succeed = true; - try { - int count = mRoomReceiptsToLoad.size(); - long start = System.currentTimeMillis(); - - while (mRoomReceiptsToLoad.size() > 0) { - String roomId; - synchronized (mRoomReceiptsToLoad) { - roomId = mRoomReceiptsToLoad.get(0); - } - - loadReceipts(roomId); - - synchronized (mRoomReceiptsToLoad) { - mRoomReceiptsToLoad.remove(0); - } - } - - saveReceipts(); - - long delta = (System.currentTimeMillis() - start); - Log.d(LOG_TAG, "loadReceipts " + count + " rooms in " + delta + " ms"); - mStoreStats.put("loadReceipts", delta); - } catch (Exception e) { - succeed = false; - //Toast.makeText(mContext, "loadReceipts failed" + e, Toast.LENGTH_LONG).show(); - Log.e(LOG_TAG, "loadReceipts failed : " + e.getMessage(), e); - } - - synchronized (this) { - mAreReceiptsReady = true; - } - - return succeed; - } - - /** - * Flush the events receipts - * - * @param roomId the roomId. - */ - private void saveReceipts(final String roomId) { - synchronized (mRoomReceiptsToLoad) { - // please wait - if (mRoomReceiptsToLoad.contains(roomId)) { - return; - } - } - - final List receipts; - - synchronized (mReceiptsByRoomIdLock) { - if (mReceiptsByRoomId.containsKey(roomId)) { - receipts = new ArrayList<>(mReceiptsByRoomId.get(roomId).values()); - } else { - receipts = null; - } - } - - // sanity check - if (null == receipts) { - return; - } - - Runnable r = new Runnable() { - @Override - public void run() { - mFileStoreHandler.post(new Runnable() { - public void run() { - if (!mIsKilled) { - long start = System.currentTimeMillis(); - writeObject("saveReceipts " + roomId, new File(mStoreRoomsMessagesReceiptsFolderFile, roomId), receipts); - Log.d(LOG_TAG, "saveReceipts : roomId " + roomId + " eventId : " + (System.currentTimeMillis() - start) + " ms"); - } - } - }); - } - }; - - Thread t = new Thread(r); - t.start(); - } - - /** - * Save the events receipts. - */ - private void saveReceipts() { - synchronized (this) { - Set roomsToCommit = mRoomsToCommitForReceipts; - - for (String roomId : roomsToCommit) { - saveReceipts(roomId); - } - - mRoomsToCommitForReceipts.clear(); - } - } - - /** - * Delete the room receipts - * - * @param roomId the room id. - */ - private void deleteRoomReceiptsFile(String roomId) { - File receiptsFile = new File(mStoreRoomsMessagesReceiptsFolderFile, roomId); - - // remove the files - if (receiptsFile.exists()) { - try { - receiptsFile.delete(); - } catch (Exception e) { - Log.e(LOG_TAG, "deleteReceiptsFile - failed " + e.getMessage(), e); - } - } - } - - //================================================================================ - // read/write methods - //================================================================================ - - /** - * Write an object in a dedicated file. - * - * @param description the operation description - * @param file the file - * @param object the object to save - * @return true if the operation succeeds - */ - private boolean writeObject(String description, File file, Object object) { - String parent = file.getParent(); - String name = file.getName(); - - File tmpFile = new File(parent, name + ".tmp"); - - if (tmpFile.exists()) { - tmpFile.delete(); - } - - if (file.exists()) { - file.renameTo(tmpFile); - } - - boolean succeed = false; - try { - FileOutputStream fos = new FileOutputStream(file); - OutputStream cos; - if (mEnableFileEncryption) { - cos = CompatUtil.createCipherOutputStream(fos, mContext); - } else { - cos = fos; - } - GZIPOutputStream gz = CompatUtil.createGzipOutputStream(cos); - ObjectOutputStream out = new ObjectOutputStream(gz); - - out.writeObject(object); - out.flush(); - out.close(); - - succeed = true; - } catch (OutOfMemoryError oom) { - dispatchOOM(oom); - } catch (Exception e) { - Log.e(LOG_TAG, "## writeObject() " + description + " : failed " + e.getMessage(), e); - } - - if (succeed) { - tmpFile.delete(); - } else { - tmpFile.renameTo(file); - } - - return succeed; - } - - /** - * Read an object from a dedicated file - * - * @param description the operation description - * @param file the file - * @return the read object if it can be retrieved - */ - private Object readObject(String description, File file) { - String parent = file.getParent(); - String name = file.getName(); - - File tmpFile = new File(parent, name + ".tmp"); - - if (tmpFile.exists()) { - Log.e(LOG_TAG, "## readObject : rescue from a tmp file " + tmpFile.getName()); - file = tmpFile; - } - - Object object = null; - try { - FileInputStream fis = new FileInputStream(file); - InputStream cis; - if (mEnableFileEncryption) { - cis = CompatUtil.createCipherInputStream(fis, mContext); - - if (cis == null) { - // fallback to unencrypted stream for backward compatibility - Log.i(LOG_TAG, "## readObject() : failed to read encrypted, fallback to unencrypted read"); - fis.close(); - cis = new FileInputStream(file); - } - } else { - cis = fis; - } - - GZIPInputStream gz = new GZIPInputStream(cis); - ObjectInputStream ois = new ObjectInputStream(gz); - object = ois.readObject(); - ois.close(); - } catch (OutOfMemoryError oom) { - dispatchOOM(oom); - } catch (Exception e) { - Log.e(LOG_TAG, "## readObject() " + description + " : failed " + e.getMessage(), e); - } - return object; - } - - - /** - * Remove the tmp files from a filename list - * - * @param names the names list - * @return the filtered list - */ - private static List listFiles(String[] names) { - List filteredFilenames = new ArrayList<>(); - List tmpFilenames = new ArrayList<>(); - - // sanity checks - // it has been reported by GA - if (null != names) { - for (int i = 0; i < names.length; i++) { - String name = names[i]; - - if (!name.endsWith(".tmp")) { - filteredFilenames.add(name); - } else { - tmpFilenames.add(name.substring(0, name.length() - ".tmp".length())); - } - } - - // check if the tmp file is not alone i.e the matched file was not saved (app crash...) - for (String tmpFileName : tmpFilenames) { - if (!filteredFilenames.contains(tmpFileName)) { - Log.e(LOG_TAG, "## listFiles() : " + tmpFileName + " does not exist but a tmp file has been retrieved"); - filteredFilenames.add(tmpFileName); - } - } - } - - return filteredFilenames; - } - - /** - * Start a runnable from the store thread - * - * @param runnable the runnable to call - */ - public void post(Runnable runnable) { - if (null != mFileStoreHandler) { - mFileStoreHandler.post(runnable); - } else { - super.post(runnable); - } - } - - //================================================================================ - // groups management - //================================================================================ - - /** - * Store a group - * - * @param group the group to store - */ - @Override - public void storeGroup(Group group) { - super.storeGroup(group); - if ((null != group) && !TextUtils.isEmpty(group.getGroupId())) { - mGroupsToCommit.add(group.getGroupId()); - } - } - - /** - * Flush a group - * - * @param group the group to store - */ - @Override - public void flushGroup(Group group) { - super.flushGroup(group); - if ((null != group) && !TextUtils.isEmpty(group.getGroupId())) { - mGroupsToCommit.add(group.getGroupId()); - saveGroups(); - } - } - - /** - * Delete a group - * - * @param groupId the groupId to delete - */ - @Override - public void deleteGroup(String groupId) { - super.deleteGroup(groupId); - if (!TextUtils.isEmpty(groupId)) { - mGroupsToCommit.add(groupId); - } - } - - /** - * Flush groups list - */ - private void saveGroups() { - // some updated rooms ? - if ((mGroupsToCommit.size() > 0) && (null != mFileStoreHandler)) { - // get the list - final Set fGroupIds = mGroupsToCommit; - mGroupsToCommit = new HashSet<>(); - - try { - Runnable r = new Runnable() { - @Override - public void run() { - mFileStoreHandler.post(new Runnable() { - public void run() { - if (!isKilled()) { - Log.d(LOG_TAG, "saveGroups " + fGroupIds.size() + " groups"); - - long start = System.currentTimeMillis(); - - for (String groupId : fGroupIds) { - Group group; - - synchronized (mGroups) { - group = mGroups.get(groupId); - } - - if (null != group) { - writeObject("saveGroup " + groupId, new File(mStoreGroupsFolderFile, groupId), group); - } else { - File tokenFile = new File(mStoreGroupsFolderFile, groupId); - - if (tokenFile.exists()) { - tokenFile.delete(); - } - } - } - - Log.d(LOG_TAG, "saveGroups done in " + (System.currentTimeMillis() - start) + " ms"); - } - } - }); - } - }; - - Thread t = new Thread(r); - t.start(); - } catch (OutOfMemoryError oom) { - Log.e(LOG_TAG, "saveGroups : failed" + oom.getMessage(), oom); - } - } - } - - /** - * Load groups from the filesystem. - * - * @return true if the operation succeeds. - */ - private boolean loadGroups() { - boolean succeed = true; - - try { - // extract the messages list - List filenames = listFiles(mStoreGroupsFolderFile.list()); - - long start = System.currentTimeMillis(); - - for (String filename : filenames) { - File groupFile = new File(mStoreGroupsFolderFile, filename); - - if (groupFile.exists()) { - Object groupAsVoid = readObject("loadGroups " + filename, groupFile); - - if ((null != groupAsVoid) && (groupAsVoid instanceof Group)) { - Group group = (Group) groupAsVoid; - mGroups.put(group.getGroupId(), group); - } else { - succeed = false; - break; - } - } - } - - if (succeed) { - long delta = (System.currentTimeMillis() - start); - Log.d(LOG_TAG, "loadGroups : " + filenames.size() + " groups in " + delta + " ms"); - mStoreStats.put("loadGroups", delta); - } - - } catch (Exception e) { - succeed = false; - Log.e(LOG_TAG, "loadGroups failed : " + e.getMessage(), e); - } - - return succeed; - } - - @Override - public void setURLPreviewEnabled(boolean value) { - super.setURLPreviewEnabled(value); - mMetaDataHasChanged = true; - } - - @Override - public void setRoomsWithoutURLPreview(Set roomIds) { - super.setRoomsWithoutURLPreview(roomIds); - mMetaDataHasChanged = true; - } - - @Override - public void setUserWidgets(Map contentDict) { - super.setUserWidgets(contentDict); - mMetaDataHasChanged = true; - } - - @Override - public void addFilter(String jsonFilter, String filterId) { - super.addFilter(jsonFilter, filterId); - mMetaDataHasChanged = true; - } - - @Override - public void setAntivirusServerPublicKey(@Nullable String key) { - super.setAntivirusServerPublicKey(key); - mMetaDataHasChanged = true; - } -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/store/MXFileStoreMetaData.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/store/MXFileStoreMetaData.java deleted file mode 100644 index 1a3f6faa..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/store/MXFileStoreMetaData.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2015 OpenMarket 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.matrix.android.internal.legacy.data.store; - -import im.vector.matrix.android.internal.legacy.rest.model.pid.ThirdPartyIdentifier; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -public class MXFileStoreMetaData implements java.io.Serializable { - // The obtained user id. - public String mUserId = null; - - // The access token to create a MXRestClient. - public String mAccessToken = null; - - // The token indicating from where to start listening event stream to get live events. - public String mEventStreamToken = null; - - //The current version of the store. - public int mVersion = -1; - - /** - * User information - */ - public String mUserDisplayName = null; - public String mUserAvatarUrl = null; - public List mThirdPartyIdentifiers = null; - public List mIgnoredUsers = new ArrayList<>(); - public Map> mDirectChatRoomsMap = null; - public boolean mIsUrlPreviewEnabled = false; - public Map mUserWidgets = new HashMap<>(); - public Set mRoomsListWithoutURLPrevew = new HashSet<>(); - - // To store known filters by the server. Keys are the filter as a Json String, Values are the filterId returned by the server - // Mainly used to store a filterId related to a corresponding Json string. - public Map mKnownFilters = new HashMap<>(); - - // crypto - public boolean mEndToEndDeviceAnnounced = false; - - public String mAntivirusServerPublicKey; - - public MXFileStoreMetaData deepCopy() { - MXFileStoreMetaData copy = new MXFileStoreMetaData(); - - copy.mUserId = mUserId; - copy.mAccessToken = mAccessToken; - copy.mEventStreamToken = mEventStreamToken; - copy.mVersion = mVersion; - copy.mUserDisplayName = mUserDisplayName; - - if (null != copy.mUserDisplayName) { - copy.mUserDisplayName.trim(); - } - - copy.mUserAvatarUrl = mUserAvatarUrl; - copy.mThirdPartyIdentifiers = mThirdPartyIdentifiers; - copy.mIgnoredUsers = mIgnoredUsers; - copy.mDirectChatRoomsMap = mDirectChatRoomsMap; - copy.mEndToEndDeviceAnnounced = mEndToEndDeviceAnnounced; - - copy.mAntivirusServerPublicKey = mAntivirusServerPublicKey; - - copy.mIsUrlPreviewEnabled = mIsUrlPreviewEnabled; - copy.mUserWidgets = mUserWidgets; - copy.mRoomsListWithoutURLPrevew = mRoomsListWithoutURLPrevew; - - copy.mKnownFilters = new HashMap<>(mKnownFilters); - - return copy; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/store/MXMemoryStore.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/store/MXMemoryStore.java deleted file mode 100644 index 92217320..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/store/MXMemoryStore.java +++ /dev/null @@ -1,1666 +0,0 @@ -/* - * Copyright 2015 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.data.store; - -import android.content.Context; -import android.os.Handler; -import android.os.Looper; -import android.support.annotation.Nullable; -import android.text.TextUtils; - -import im.vector.matrix.android.api.auth.data.Credentials; -import im.vector.matrix.android.internal.legacy.MXDataHandler; -import im.vector.matrix.android.internal.legacy.data.Room; -import im.vector.matrix.android.internal.legacy.data.RoomAccountData; -import im.vector.matrix.android.internal.legacy.data.RoomSummary; -import im.vector.matrix.android.internal.legacy.data.comparator.Comparators; -import im.vector.matrix.android.internal.legacy.data.metrics.MetricsListener; -import im.vector.matrix.android.internal.legacy.data.timeline.EventTimeline; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.ReceiptData; -import im.vector.matrix.android.internal.legacy.rest.model.RoomMember; -import im.vector.matrix.android.internal.legacy.rest.model.TokensChunkEvents; -import im.vector.matrix.android.internal.legacy.rest.model.User; -import im.vector.matrix.android.internal.legacy.rest.model.group.Group; -import im.vector.matrix.android.internal.legacy.rest.model.pid.ThirdPartyIdentifier; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -/** - * An in-memory IMXStore. - */ -public class MXMemoryStore implements IMXStore { - - private static final String LOG_TAG = MXMemoryStore.class.getSimpleName(); - - protected Map mRooms; - protected Map mUsers; - - protected static final Object mRoomEventsLock = new Object(); - - // room id -> map of (event_id -> event) events for this room (linked so insertion order is preserved) - protected Map> mRoomEvents; - - protected Map mRoomTokens; - - protected Map mRoomSummaries; - protected Map mRoomAccountData; - - // dict of dict of MXReceiptData indexed by userId - protected final Object mReceiptsByRoomIdLock = new Object(); - protected Map> mReceiptsByRoomId; - - protected Map mGroups; - - // room state events - //protected final Map> mRoomStateEventsByRoomId = new HashMap<>(); - - // common context - private static Context mSharedContext = null; - - // the context - protected Context mContext; - - // - private final Map mTemporaryEventsList = new HashMap<>(); - protected MetricsListener mMetricsListener; - - protected Credentials mCredentials; - - protected String mEventStreamToken = null; - - protected final List mListeners = new ArrayList<>(); - - // Meta data about the store. It is defined only if the passed MXCredentials contains all information. - // When nil, nothing is stored on the file system. - protected MXFileStoreMetaData mMetadata = null; - - // last time the avatar / displayname was updated - protected long mUserDisplayNameTs; - protected long mUserAvatarUrlTs; - - // DataHandler -- added waiting to be refactored - private MXDataHandler mDataHandler; - - /** - * Initialization method. - */ - protected void initCommon() { - mRooms = new ConcurrentHashMap<>(); - mUsers = new ConcurrentHashMap<>(); - mRoomEvents = new ConcurrentHashMap<>(); - mRoomTokens = new ConcurrentHashMap<>(); - mRoomSummaries = new ConcurrentHashMap<>(); - mReceiptsByRoomId = new ConcurrentHashMap<>(); - mRoomAccountData = new ConcurrentHashMap<>(); - mGroups = new ConcurrentHashMap<>(); - mEventStreamToken = null; - } - - public MXMemoryStore() { - initCommon(); - } - - /** - * Set the application context - * - * @param context the context - */ - protected void setContext(Context context) { - if (null == mSharedContext) { - if (null != context) { - mSharedContext = context.getApplicationContext(); - } else { - throw new RuntimeException("MXMemoryStore : context cannot be null"); - } - } - - mContext = mSharedContext; - } - - /** - * Default constructor - * - * @param credentials the expected getCredentials - * @param context the context - */ - public MXMemoryStore(Credentials credentials, Context context) { - initCommon(); - - setContext(context); - mCredentials = credentials; - - mMetadata = new MXFileStoreMetaData(); - } - - @Override - public Context getContext() { - return mContext; - } - - /** - * Save changes in the store. - * If the store uses permanent storage like database or file, it is the optimised time - * to commit the last changes. - */ - @Override - public void commit() { - } - - /** - * Open the store. - */ - public void open() { - } - - /** - * Close the store. - * Any pending operation must be complete in this call. - */ - @Override - public void close() { - } - - /** - * Clear the store. - * Any pending operation must be complete in this call. - */ - @Override - public void clear() { - initCommon(); - } - - /** - * Indicate if the MXStore implementation stores data permanently. - * Permanent storage allows the SDK to make less requests at the startup. - * - * @return true if permanent. - */ - @Override - public boolean isPermanent() { - return false; - } - - /** - * Check if the initial load is performed. - * - * @return true if it is ready. - */ - @Override - public boolean isReady() { - return true; - } - - /** - * Check if the read receipts are ready to be used. - * - * @return true if they are ready. - */ - @Override - public boolean areReceiptsReady() { - return true; - } - - /** - * @return true if the store is corrupted. - */ - @Override - public boolean isCorrupted() { - return false; - } - - /** - * Warn that the store data are corrupted. - * It might append if an update request failed. - * - * @param reason the corruption reason - */ - @Override - public void setCorrupted(String reason) { - dispatchOnStoreCorrupted(mCredentials.getUserId(), reason); - } - - /** - * Returns to disk usage size in bytes. - * - * @return disk usage size - */ - @Override - public long diskUsage() { - return 0; - } - - /** - * Returns the latest known event stream token - * - * @return the event stream token - */ - @Override - public String getEventStreamToken() { - return mEventStreamToken; - } - - /** - * Set the event stream token. - * - * @param token the event stream token - */ - @Override - public void setEventStreamToken(String token) { - if (null != mMetadata) { - mMetadata.mEventStreamToken = token; - } - mEventStreamToken = token; - } - - @Override - public void addMXStoreListener(IMXStoreListener listener) { - synchronized (this) { - if ((null != listener) && (mListeners.indexOf(listener) < 0)) { - mListeners.add(listener); - } - } - } - - @Override - public void removeMXStoreListener(IMXStoreListener listener) { - synchronized (this) { - if (null != listener) { - mListeners.remove(listener); - } - } - } - - /** - * profile information - */ - @Override - public String displayName() { - if (null != mMetadata) { - return mMetadata.mUserDisplayName; - } else { - return null; - } - } - - @Override - public boolean setDisplayName(String displayName, long ts) { - boolean isUpdated; - - synchronized (LOG_TAG) { - if (null != mMetadata) { - Log.d(LOG_TAG, "## setDisplayName() : from " + mMetadata.mUserDisplayName + " to " + displayName + " ts " + ts); - } - - isUpdated = (null != mMetadata) - && !TextUtils.equals(mMetadata.mUserDisplayName, displayName) - && (mUserDisplayNameTs < ts) - && (ts != 0) - && (ts <= System.currentTimeMillis()); - - if (isUpdated) { - mMetadata.mUserDisplayName = (null != displayName) ? displayName.trim() : null; - mUserDisplayNameTs = ts; - - // update the cached oneself User - User myUser = getUser(mMetadata.mUserId); - - if (null != myUser) { - myUser.displayname = mMetadata.mUserDisplayName; - } - - Log.d(LOG_TAG, "## setDisplayName() : updated"); - commit(); - } - } - - return isUpdated; - } - - @Override - public String avatarURL() { - if (null != mMetadata) { - return mMetadata.mUserAvatarUrl; - } else { - return null; - } - } - - @Override - public boolean setAvatarURL(String avatarURL, long ts) { - boolean isUpdated = false; - - synchronized (LOG_TAG) { - if (null != mMetadata) { - Log.d(LOG_TAG, "## setAvatarURL() : from " + mMetadata.mUserAvatarUrl + " to " + avatarURL + " ts " + ts); - } - - isUpdated = (null != mMetadata) && !TextUtils.equals(mMetadata.mUserAvatarUrl, avatarURL) - && (mUserAvatarUrlTs < ts) && (ts != 0) && (ts <= System.currentTimeMillis()); - - if (isUpdated) { - mMetadata.mUserAvatarUrl = avatarURL; - mUserAvatarUrlTs = ts; - - // update the cached oneself User - User myUser = getUser(mMetadata.mUserId); - - if (null != myUser) { - myUser.setAvatarUrl(avatarURL); - } - - Log.d(LOG_TAG, "## setAvatarURL() : updated"); - commit(); - } - } - - return isUpdated; - } - - @Override - public List thirdPartyIdentifiers() { - if (null != mMetadata) { - return mMetadata.mThirdPartyIdentifiers; - } else { - return new ArrayList<>(); - } - } - - @Override - public void setThirdPartyIdentifiers(List identifiers) { - if (null != mMetadata) { - mMetadata.mThirdPartyIdentifiers = identifiers; - - Log.d(LOG_TAG, "setThirdPartyIdentifiers : commit"); - commit(); - } - } - - @Override - public List getIgnoredUserIdsList() { - if (null != mMetadata) { - return mMetadata.mIgnoredUsers; - } else { - return new ArrayList<>(); - } - } - - @Override - public void setIgnoredUserIdsList(List users) { - if (null != mMetadata) { - mMetadata.mIgnoredUsers = users; - Log.d(LOG_TAG, "setIgnoredUserIdsList : commit"); - commit(); - } - } - - @Override - public Map> getDirectChatRoomsDict() { - return mMetadata.mDirectChatRoomsMap; - } - - @Override - public void setDirectChatRoomsDict(Map> directChatRoomsDict) { - if (null != mMetadata) { - mMetadata.mDirectChatRoomsMap = directChatRoomsDict; - Log.d(LOG_TAG, "setDirectChatRoomsDict : commit"); - commit(); - } - } - - @Override - public Collection getRooms() { - return new ArrayList<>(mRooms.values()); - } - - @Override - public Collection getUsers() { - Collection users; - - synchronized (mUsers) { - users = new ArrayList<>(mUsers.values()); - } - - return users; - } - - @Override - public Room getRoom(String roomId) { - if (null != roomId) { - return mRooms.get(roomId); - } else { - return null; - } - } - - @Override - public User getUser(String userId) { - if (null != userId) { - User user; - - synchronized (mUsers) { - user = mUsers.get(userId); - } - - return user; - } else { - return null; - } - } - - @Override - public void storeUser(User user) { - if ((null != user) && (null != user.user_id)) { - try { - synchronized (mUsers) { - mUsers.put(user.user_id, user); - } - } catch (OutOfMemoryError e) { - dispatchOOM(e); - } - } - } - - /** - * Update the user information from a room member. - * - * @param roomMember the room member. - */ - @Override - public void updateUserWithRoomMemberEvent(RoomMember roomMember) { - try { - if (null != roomMember) { - User user = getUser(roomMember.getUserId()); - - // if the user does not exist, create it - if (null == user) { - user = new User(); - user.user_id = roomMember.getUserId(); - user.setRetrievedFromRoomMember(); - storeUser(user); - } - - // update the display name and the avatar url. - // the leave and ban events have no displayname and no avatar url. - if (TextUtils.equals(roomMember.membership, RoomMember.MEMBERSHIP_JOIN)) { - boolean hasUpdates = !TextUtils.equals(user.displayname, roomMember.displayname) - || !TextUtils.equals(user.getAvatarUrl(), roomMember.getAvatarUrl()); - - if (hasUpdates) { - // invite event does not imply that the user uses the application. - // but if the presence is set to 0, it means that the user information is not initialized - if (user.getLatestPresenceTs() < roomMember.getOriginServerTs()) { - // if the user joined the room, it implies that he used the application - user.displayname = roomMember.displayname; - user.setAvatarUrl(roomMember.getAvatarUrl()); - user.setLatestPresenceTs(roomMember.getOriginServerTs()); - user.setRetrievedFromRoomMember(); - } - } - } - } - } catch (OutOfMemoryError oom) { - dispatchOOM(oom); - Log.e(LOG_TAG, "## updateUserWithRoomMemberEvent() failed " + oom.getMessage(), oom); - } catch (Exception e) { - Log.e(LOG_TAG, "## updateUserWithRoomMemberEvent() failed " + e.getMessage(), e); - } - } - - @Override - public void storeRoom(Room room) { - if ((null != room) && (null != room.getRoomId())) { - mRooms.put(room.getRoomId(), room); - - // defines a default back token - if (!mRoomTokens.containsKey(room.getRoomId())) { - storeBackToken(room.getRoomId(), ""); - } - } - } - - @Override - public Event getOldestEvent(String roomId) { - Event event = null; - - if (null != roomId) { - synchronized (mRoomEventsLock) { - LinkedHashMap events = mRoomEvents.get(roomId); - - if (events != null) { - Iterator it = events.values().iterator(); - if (it.hasNext()) { - event = it.next(); - } - } - } - } - - return event; - } - - /** - * Get the latest event from the given room (to update summary for example) - * - * @param roomId the room id - * @return the event - */ - @Override - public Event getLatestEvent(String roomId) { - Event event = null; - - if (null != roomId) { - synchronized (mRoomEventsLock) { - LinkedHashMap events = mRoomEvents.get(roomId); - - if (events != null) { - Iterator it = events.values().iterator(); - if (it.hasNext()) { - Event lastEvent = null; - - while (it.hasNext()) { - lastEvent = it.next(); - } - - event = lastEvent; - } - } - } - } - return event; - } - - /** - * Count the number of events after the provided events id - * - * @param roomId the room id. - * @param eventId the event id to find. - * @return the events count after this event if - */ - @Override - public int eventsCountAfter(String roomId, String eventId) { - return eventsAfter(roomId, eventId, mCredentials.getUserId(), null).size(); - } - - @Override - public void storeLiveRoomEvent(Event event) { - try { - if ((null != event) && (null != event.roomId) && (null != event.eventId)) { - synchronized (mRoomEventsLock) { - LinkedHashMap events = mRoomEvents.get(event.roomId); - - // create the list it does not exist - if (null == events) { - events = new LinkedHashMap<>(); - mRoomEvents.put(event.roomId, events); - } else if (events.containsKey(event.eventId)) { - // the event is already define - return; - } else if (!event.isDummyEvent() && (mTemporaryEventsList.size() > 0)) { - // remove any waiting echo event - String dummyKey = null; - - for (String key : mTemporaryEventsList.keySet()) { - Event eventToCheck = mTemporaryEventsList.get(key); - if (TextUtils.equals(eventToCheck.eventId, event.eventId)) { - dummyKey = key; - break; - } - } - - if (null != dummyKey) { - events.remove(dummyKey); - mTemporaryEventsList.remove(dummyKey); - } - } - - // If we don't have any information on this room - a pagination token, namely - we don't store the event but instead - // wait for the first pagination request to set things right - events.put(event.eventId, event); - - if (event.isDummyEvent()) { - mTemporaryEventsList.put(event.eventId, event); - } - } - } - } catch (OutOfMemoryError e) { - dispatchOOM(e); - } - } - - @Override - public boolean doesEventExist(String eventId, String roomId) { - boolean res = false; - - if (!TextUtils.isEmpty(eventId) && !TextUtils.isEmpty(roomId)) { - synchronized (mRoomEventsLock) { - res = mRoomEvents.containsKey(roomId) && mRoomEvents.get(roomId).containsKey(eventId); - } - } - - return res; - } - - @Override - public Event getEvent(String eventId, String roomId) { - Event event = null; - - if (!TextUtils.isEmpty(eventId) && !TextUtils.isEmpty(roomId)) { - synchronized (mRoomEventsLock) { - LinkedHashMap events = mRoomEvents.get(roomId); - - if (events != null) { - event = events.get(eventId); - } - } - } - - return event; - } - - @Override - public void deleteEvent(Event event) { - if ((null != event) && (null != event.roomId) && (event.eventId != null)) { - synchronized (mRoomEventsLock) { - LinkedHashMap events = mRoomEvents.get(event.roomId); - if (events != null) { - events.remove(event.eventId); - } - } - } - } - - @Override - public void deleteRoom(String roomId) { - // sanity check - if (null != roomId) { - deleteRoomData(roomId); - synchronized (mRoomEventsLock) { - mRooms.remove(roomId); - } - } - } - - @Override - public void deleteRoomData(String roomId) { - // sanity check - if (null != roomId) { - synchronized (mRoomEventsLock) { - mRoomEvents.remove(roomId); - mRoomTokens.remove(roomId); - mRoomSummaries.remove(roomId); - mRoomAccountData.remove(roomId); - mReceiptsByRoomId.remove(roomId); - } - } - } - - /** - * Remove all sent messages in a room. - * - * @param roomId the id of the room. - * @param keepUnsent set to true to do not delete the unsent message - */ - @Override - public void deleteAllRoomMessages(String roomId, boolean keepUnsent) { - // sanity check - if (null != roomId) { - synchronized (mRoomEventsLock) { - - if (keepUnsent) { - LinkedHashMap eventMap = mRoomEvents.get(roomId); - - if (null != eventMap) { - List events = new ArrayList<>(eventMap.values()); - - for (Event event : events) { - if (event.mSentState == Event.SentState.SENT) { - if (null != event.eventId) { - eventMap.remove(event.eventId); - } - } - } - } - } else { - mRoomEvents.remove(roomId); - } - - mRoomSummaries.remove(roomId); - } - } - } - - @Override - public void flushRoomEvents(String roomId) { - // NOP - } - - @Override - public void storeRoomEvents(String roomId, TokensChunkEvents tokensChunkEvents, EventTimeline.Direction direction) { - try { - if (null != roomId) { - synchronized (mRoomEventsLock) { - LinkedHashMap events = mRoomEvents.get(roomId); - if (events == null) { - events = new LinkedHashMap<>(); - mRoomEvents.put(roomId, events); - } - - if (direction == EventTimeline.Direction.FORWARDS) { - mRoomTokens.put(roomId, tokensChunkEvents.start); - - for (Event event : tokensChunkEvents.chunk) { - events.put(event.eventId, event); - } - } else { // BACKWARD - Collection eventsList = events.values(); - - // no stored events - if (events.size() == 0) { - // insert the catchup events in reverse order - for (int index = tokensChunkEvents.chunk.size() - 1; index >= 0; index--) { - Event backEvent = tokensChunkEvents.chunk.get(index); - events.put(backEvent.eventId, backEvent); - } - - // define a token - mRoomTokens.put(roomId, tokensChunkEvents.start); - } else { - LinkedHashMap events2 = new LinkedHashMap<>(); - - // insert the catchup events in reverse order - for (int index = tokensChunkEvents.chunk.size() - 1; index >= 0; index--) { - Event backEvent = tokensChunkEvents.chunk.get(index); - events2.put(backEvent.eventId, backEvent); - } - - // add the previous added Events - for (Event event : eventsList) { - events2.put(event.eventId, event); - } - - // store the new list - mRoomEvents.put(roomId, events2); - } - } - } - } - } catch (OutOfMemoryError e) { - dispatchOOM(e); - } - } - - /** - * Store the back token of a room. - * - * @param roomId the room id. - * @param backToken the back token - */ - @Override - public void storeBackToken(String roomId, String backToken) { - if ((null != roomId) && (null != backToken)) { - mRoomTokens.put(roomId, backToken); - } - } - - @Override - public void flushSummary(RoomSummary summary) { - } - - @Override - public void flushSummaries() { - } - - @Override - public void storeSummary(RoomSummary summary) { - try { - if ((null != summary) && (null != summary.getRoomId())) { - mRoomSummaries.put(summary.getRoomId(), summary); - } - } catch (OutOfMemoryError e) { - dispatchOOM(e); - } - } - - @Override - public void storeAccountData(String roomId, RoomAccountData accountData) { - try { - if (null != roomId) { - Room room = mRooms.get(roomId); - - // sanity checks - if ((room != null) && (null != accountData)) { - mRoomAccountData.put(roomId, accountData); - } - } - } catch (OutOfMemoryError e) { - dispatchOOM(e); - } - } - - @Override - public void storeLiveStateForRoom(String roomId) { - } - - @Override - public void storeRoomStateEvent(String roomId, im.vector.matrix.android.api.session.events.model.Event event) { - /*synchronized (mRoomStateEventsByRoomId) { - Map events = mRoomStateEventsByRoomId.get(roomId); - - if (null == events) { - events = new HashMap<>(); - mRoomStateEventsByRoomId.put(roomId, events); - } - - // keeps the latest state events - if (null != event.stateKey) { - events.put(event.stateKey, event); - } - }*/ - } - - @Override - public void getRoomStateEvents(final String roomId, final ApiCallback> callback) { - final List events = new ArrayList<>(); - - /*synchronized (mRoomStateEventsByRoomId) { - if (mRoomStateEventsByRoomId.containsKey(roomId)) { - events.addAll(mRoomStateEventsByRoomId.get(roomId).values()); - } - }*/ - - (new Handler(Looper.getMainLooper())).post(new Runnable() { - @Override - public void run() { - callback.onSuccess(events); - } - }); - } - - /** - * Retrieve all non-state room events for this room. - * - * @param roomId The room ID - * @return A collection of events. null if there is no cached event. - */ - @Override - public Collection getRoomMessages(final String roomId) { - // sanity check - if (null == roomId) { - return null; - } - - Collection collection = null; - - synchronized (mRoomEventsLock) { - LinkedHashMap events = mRoomEvents.get(roomId); - - if (null != events) { - collection = new ArrayList<>(events.values()); - } - } - - return collection; - } - - @Override - public TokensChunkEvents getEarlierMessages(final String roomId, final String fromToken, final int limit) { - // For now, we return everything we have for the original null token request - // For older requests (providing a token), returning null for now - if (null != roomId) { - List eventsList; - - synchronized (mRoomEventsLock) { - LinkedHashMap events = mRoomEvents.get(roomId); - if ((events == null) || (events.size() == 0)) { - return null; - } - - // reach the end of the stored items - if (TextUtils.equals(mRoomTokens.get(roomId), fromToken)) { - return null; - } - - // check if the token is known in the sublist - eventsList = new ArrayList<>(events.values()); - } - - - List subEventsList = new ArrayList<>(); - - // search from the latest to the oldest events - Collections.reverse(eventsList); - - TokensChunkEvents response = new TokensChunkEvents(); - - // start the latest event and there is enough events to provide to the caller ? - if ((null == fromToken) && (eventsList.size() <= limit)) { - subEventsList = eventsList; - } else { - int index = 0; - - if (null != fromToken) { - // search if token is one of the stored events - for (; (index < eventsList.size()) && (!TextUtils.equals(fromToken, eventsList.get(index).mToken)); index++) - ; - - index++; - } - - // found it ? - if (index < eventsList.size()) { - for (; index < eventsList.size(); index++) { - Event event = eventsList.get(index); - subEventsList.add(event); - - // loop until to find an event with a token - if ((subEventsList.size() >= limit) && (event.mToken != null)) { - break; - } - } - } - } - - // unknown token - if (subEventsList.size() == 0) { - return null; - } - - response.chunk = subEventsList; - - Event firstEvent = subEventsList.get(0); - Event lastEvent = subEventsList.get(subEventsList.size() - 1); - - response.start = firstEvent.mToken; - - // unknown last event token, use the latest known one - if ((null == lastEvent.mToken) && !TextUtils.isEmpty(mRoomTokens.get(roomId))) { - lastEvent.mToken = mRoomTokens.get(roomId); - } - - response.end = lastEvent.mToken; - - return response; - } - return null; - } - - @Override - public Collection getSummaries() { - List summaries = new ArrayList<>(); - - for (String roomId : mRoomSummaries.keySet()) { - Room room = mRooms.get(roomId); - if (null != room) { - if (!room.isJoined() && !room.isInvited()) { - Log.e(LOG_TAG, "## getSummaries() : a summary exists for the roomId " + roomId + " but the user is not anymore a member"); - } else { - summaries.add(mRoomSummaries.get(roomId)); - } - } else { - Log.e(LOG_TAG, "## getSummaries() : a summary exists for the roomId " + roomId + " but it does not exist in the room list"); - } - } - - return summaries; - } - - @Nullable - @Override - public RoomSummary getSummary(String roomId) { - // sanity check - if (null == roomId) { - return null; - } - - Room room = mRooms.get(roomId); - if (null != room) { - return mRoomSummaries.get(roomId); - } else { - Log.e(LOG_TAG, "## getSummary() : a summary exists for the roomId " + roomId + " but it does not exist in the room list"); - } - - return null; - } - - @Override - public List getLatestUnsentEvents(String roomId) { - if (null == roomId) { - return null; - } - - List unsentRoomEvents = new ArrayList<>(); - - synchronized (mRoomEventsLock) { - LinkedHashMap events = mRoomEvents.get(roomId); - - // contain some events - if ((null != events) && (events.size() > 0)) { - List eventsList = new ArrayList<>(events.values()); - - for (int index = events.size() - 1; index >= 0; index--) { - Event event = eventsList.get(index); - - if (event.mSentState == Event.SentState.WAITING_RETRY) { - unsentRoomEvents.add(event); - } else { - //break; - } - } - - Collections.reverse(unsentRoomEvents); - } - } - - return unsentRoomEvents; - } - - @Override - public List getUndeliveredEvents(String roomId) { - if (null == roomId) { - return null; - } - - List undeliveredEvents = new ArrayList<>(); - - synchronized (mRoomEventsLock) { - LinkedHashMap events = mRoomEvents.get(roomId); - - // contain some events - if ((null != events) && (events.size() > 0)) { - List eventsList = new ArrayList<>(events.values()); - - for (int index = 0; index < events.size(); index++) { - Event event = eventsList.get(index); - - if (event.isUndelivered()) { - undeliveredEvents.add(event); - } - } - } - } - - return undeliveredEvents; - } - - @Override - public List getUnknownDeviceEvents(String roomId) { - if (null == roomId) { - return null; - } - - List unknownDeviceEvents = new ArrayList<>(); - - synchronized (mRoomEventsLock) { - LinkedHashMap events = mRoomEvents.get(roomId); - - // contain some events - if ((null != events) && (events.size() > 0)) { - List eventsList = new ArrayList<>(events.values()); - - for (int index = 0; index < events.size(); index++) { - Event event = eventsList.get(index); - - if (event.isUnknownDevice()) { - unknownDeviceEvents.add(event); - } - } - } - } - - return unknownDeviceEvents; - } - - /** - * Returns the receipts list for an event in a dedicated room. - * if sort is set to YES, they are sorted from the latest to the oldest ones. - * - * @param roomId The room Id. - * @param eventId The event Id. (null to retrieve all existing receipts) - * @param excludeSelf exclude the oneself read receipts. - * @param sort to sort them from the latest to the oldest - * @return the receipts for an event in a dedicated room. - */ - @Override - public List getEventReceipts(String roomId, String eventId, boolean excludeSelf, boolean sort) { - List receipts = new ArrayList<>(); - - synchronized (mReceiptsByRoomIdLock) { - if (mReceiptsByRoomId.containsKey(roomId)) { - String myUserID = mCredentials.getUserId(); - - Map receiptsByUserId = mReceiptsByRoomId.get(roomId); - // copy the user id list to avoid having update while looping - List userIds = new ArrayList<>(receiptsByUserId.keySet()); - - if (null == eventId) { - receipts.addAll(receiptsByUserId.values()); - } else { - for (String userId : userIds) { - if (receiptsByUserId.containsKey(userId) && (!excludeSelf || !TextUtils.equals(myUserID, userId))) { - ReceiptData receipt = receiptsByUserId.get(userId); - - if (TextUtils.equals(receipt.eventId, eventId)) { - receipts.add(receipt); - } - } - } - } - } - } - - if (sort && (receipts.size() > 0)) { - Collections.sort(receipts, Comparators.descComparator); - } - - return receipts; - } - - /** - * Store the receipt for an user in a room. - * The receipt validity is checked i.e the receipt is not for an already read message. - * - * @param receipt The event - * @param roomId The roomId - * @return true if the receipt has been stored - */ - @Override - public boolean storeReceipt(ReceiptData receipt, String roomId) { - try { - // sanity check - if (TextUtils.isEmpty(roomId) || (null == receipt)) { - return false; - } - - Map receiptsByUserId; - - //Log.d(LOG_TAG, "## storeReceipt() : roomId " + roomId + " userId " + receipt.userId + " eventId " + receipt.eventId - // + " originServerTs " + receipt.originServerTs); - - synchronized (mReceiptsByRoomIdLock) { - if (!mReceiptsByRoomId.containsKey(roomId)) { - receiptsByUserId = new HashMap<>(); - mReceiptsByRoomId.put(roomId, receiptsByUserId); - } else { - receiptsByUserId = mReceiptsByRoomId.get(roomId); - } - } - - ReceiptData curReceipt = null; - - if (receiptsByUserId.containsKey(receipt.userId)) { - curReceipt = receiptsByUserId.get(receipt.userId); - } - - if (null == curReceipt) { - //Log.d(LOG_TAG, "## storeReceipt() : there was no receipt from this user"); - receiptsByUserId.put(receipt.userId, receipt); - return true; - } - - if (TextUtils.equals(receipt.eventId, curReceipt.eventId)) { - //Log.d(LOG_TAG, "## storeReceipt() : receipt for the same event"); - return false; - } - - if (receipt.originServerTs < curReceipt.originServerTs) { - //Log.d(LOG_TAG, "## storeReceipt() : the receipt is older that the current one"); - return false; - } - - // check if the read receipt is not for an already read message - if (TextUtils.equals(receipt.userId, mCredentials.getUserId())) { - synchronized (mReceiptsByRoomIdLock) { - LinkedHashMap eventsMap = mRoomEvents.get(roomId); - - // test if the event is know - if ((null != eventsMap) && eventsMap.containsKey(receipt.eventId)) { - List eventIds = new ArrayList<>(eventsMap.keySet()); - - int curEventPos = eventIds.indexOf(curReceipt.eventId); - int newEventPos = eventIds.indexOf(receipt.eventId); - - if (curEventPos >= newEventPos) { - Log.d(LOG_TAG, "## storeReceipt() : the read message is already read (cur pos " + curEventPos - + " receipt event pos " + newEventPos + ")"); - return false; - } - } - } - } - - //Log.d(LOG_TAG, "## storeReceipt() : updated"); - receiptsByUserId.put(receipt.userId, receipt); - } catch (OutOfMemoryError e) { - dispatchOOM(e); - } - - return true; - } - - /** - * Get the receipt for an user in a dedicated room. - * - * @param roomId the room id. - * @param userId the user id. - * @return the dedicated receipt - */ - @Override - public ReceiptData getReceipt(String roomId, String userId) { - ReceiptData res = null; - - // sanity checks - if (!TextUtils.isEmpty(roomId) && !TextUtils.isEmpty(userId)) { - synchronized (mReceiptsByRoomIdLock) { - if (mReceiptsByRoomId.containsKey(roomId)) { - Map receipts = mReceiptsByRoomId.get(roomId); - res = receipts.get(userId); - } - } - } - - return res; - } - - /** - * Return a list of stored events after the parameter one. - * It could the ones sent by the user excludedUserId. - * A filter can be applied to ignore some event (Event.EVENT_TYPE_...). - * - * @param roomId the roomId - * @param eventId the start event Id. - * @param excludedUserId the excluded user id - * @param allowedTypes the filtered event type (null to allow anyone) - * @return the evnts list - */ - private List eventsAfter(String roomId, String eventId, String excludedUserId, List allowedTypes) { - // events list - List events = new ArrayList<>(); - - // sanity check - if (null != roomId) { - synchronized (mRoomEventsLock) { - LinkedHashMap roomEvents = mRoomEvents.get(roomId); - - if (roomEvents != null) { - List linkedEvents = new ArrayList<>(roomEvents.values()); - - // Check messages from the most recent - for (int i = linkedEvents.size() - 1; i >= 0; i--) { - Event event = linkedEvents.get(i); - - if ((null == eventId) || !TextUtils.equals(event.eventId, eventId)) { - // Keep events matching filters - if ((null == allowedTypes || (allowedTypes.indexOf(event.getType()) >= 0)) - && !TextUtils.equals(event.getSender(), excludedUserId)) { - events.add(event); - } - } else { - // We are done - break; - } - } - - // filter the unread messages - // some messages are not defined as unreadable - for (int index = 0; index < events.size(); index++) { - Event event = events.get(index); - - if (TextUtils.equals(event.getSender(), mCredentials.getUserId()) || TextUtils.equals(event.getType(), Event.EVENT_TYPE_STATE_ROOM_MEMBER)) { - events.remove(index); - index--; - } - } - - Collections.reverse(events); - } - } - } - - return events; - } - - /** - * Check if an event has been read by an user. - * - * @param roomId the room Id - * @param userId the user id - * @param eventIdTotest the event id - * @return true if the user has read the message. - */ - @Override - public boolean isEventRead(String roomId, String userId, String eventIdTotest) { - boolean res = false; - - // sanity check - if ((null != roomId) && (null != userId)) { - synchronized (mReceiptsByRoomIdLock) { - synchronized (mRoomEventsLock) { - if (mReceiptsByRoomId.containsKey(roomId) && mRoomEvents.containsKey(roomId)) { - Map receiptsByUserId = mReceiptsByRoomId.get(roomId); - LinkedHashMap eventsMap = mRoomEvents.get(roomId); - - // check if the event is known - if (eventsMap.containsKey(eventIdTotest) && receiptsByUserId.containsKey(userId)) { - ReceiptData data = receiptsByUserId.get(userId); - List eventIds = new ArrayList<>(eventsMap.keySet()); - - // the message has been read if it was sent before the latest read one - res = eventIds.indexOf(eventIdTotest) <= eventIds.indexOf(data.eventId); - } else if (receiptsByUserId.containsKey(userId)) { - // the event is not known so assume it is has been flushed - res = true; - } - } - } - } - } - - return res; - } - - /** - * Provides the unread events list. - * - * @param roomId the room id. - * @param types an array of event types strings (Event.EVENT_TYPE_XXX). - * @return the unread events list. - */ - @Override - public List unreadEvents(String roomId, List types) { - List res = null; - - synchronized (mReceiptsByRoomIdLock) { - if (mReceiptsByRoomId.containsKey(roomId)) { - Map receiptsByUserId = mReceiptsByRoomId.get(roomId); - - if (receiptsByUserId.containsKey(mCredentials.getUserId())) { - ReceiptData data = receiptsByUserId.get(mCredentials.getUserId()); - - res = eventsAfter(roomId, data.eventId, mCredentials.getUserId(), types); - } - } - } - - if (null == res) { - res = new ArrayList<>(); - } - - return res; - } - - /** - * @return the current listeners - */ - private List getListeners() { - List listeners; - - synchronized (this) { - listeners = new ArrayList<>(mListeners); - } - - return listeners; - } - - /** - * Dispatch postProcess - * - * @param accountId the account id - */ - protected void dispatchPostProcess(String accountId) { - List listeners = getListeners(); - - for (IMXStoreListener listener : listeners) { - listener.postProcess(accountId); - } - } - - /** - * Dispatch store ready - * - * @param accountId the account id - */ - protected void dispatchOnStoreReady(String accountId) { - List listeners = getListeners(); - - for (IMXStoreListener listener : listeners) { - listener.onStoreReady(accountId); - } - } - - /** - * Dispatch that the store is corrupted - * - * @param accountId the account id - * @param description the error description - */ - protected void dispatchOnStoreCorrupted(String accountId, String description) { - List listeners = getListeners(); - - for (IMXStoreListener listener : listeners) { - listener.onStoreCorrupted(accountId, description); - } - } - - /** - * Dispatch an out of memory error. - * - * @param e the out of memory error - */ - protected void dispatchOOM(OutOfMemoryError e) { - List listeners = getListeners(); - - for (IMXStoreListener listener : listeners) { - listener.onStoreOOM(mCredentials.getUserId(), e.getMessage()); - } - } - - /** - * Dispatch the read receipts loading. - * - * @param roomId the room id. - */ - protected void dispatchOnReadReceiptsLoaded(String roomId) { - List listeners = getListeners(); - - for (IMXStoreListener listener : listeners) { - listener.onReadReceiptsLoaded(roomId); - } - } - - /** - * Provides the store preload time in milliseconds. - * - * @return the store preload time in milliseconds. - */ - @Override - public long getPreloadTime() { - return 0; - } - - /** - * Provides some store stats - * - * @return the store stats - */ - @Override - public Map getStats() { - return new HashMap<>(); - } - - /** - * Start a runnable from the store thread - * - * @param runnable the runnable to call - */ - @Override - public void post(Runnable runnable) { - new Handler(Looper.getMainLooper()).post(runnable); - } - - /** - * Store a group - * - * @param group the group to store - */ - @Override - public void storeGroup(Group group) { - if ((null != group) && !TextUtils.isEmpty(group.getGroupId())) { - synchronized (mGroups) { - mGroups.put(group.getGroupId(), group); - } - } - } - - /** - * Flush a group - * - * @param group the group to store - */ - @Override - public void flushGroup(Group group) { - } - - /** - * Delete a group - * - * @param groupId the groupId to delete - */ - @Override - public void deleteGroup(String groupId) { - if (!TextUtils.isEmpty(groupId)) { - synchronized (mGroups) { - mGroups.remove(groupId); - } - } - } - - /** - * Retrieve a group from its id. - * - * @param groupId the group id - * @return the group if it exists - */ - @Override - public Group getGroup(String groupId) { - synchronized (mGroups) { - return (null != groupId) ? mGroups.get(groupId) : null; - } - } - - /** - * @return the stored groups - */ - @Override - public Collection getGroups() { - synchronized (mGroups) { - return mGroups.values(); - } - } - - @Override - public void setURLPreviewEnabled(boolean value) { - mMetadata.mIsUrlPreviewEnabled = value; - } - - @Override - public boolean isURLPreviewEnabled() { - return mMetadata.mIsUrlPreviewEnabled; - } - - @Override - public void setRoomsWithoutURLPreview(Set roomIds) { - mMetadata.mRoomsListWithoutURLPrevew = roomIds; - } - - @Override - public void setUserWidgets(Map contentDict) { - mMetadata.mUserWidgets = contentDict; - } - - @Override - public Map getUserWidgets() { - return mMetadata.mUserWidgets; - } - - @Override - public Set getRoomsWithoutURLPreviews() { - return (null != mMetadata.mRoomsListWithoutURLPrevew) ? mMetadata.mRoomsListWithoutURLPrevew : new HashSet(); - } - - @Override - public void addFilter(String jsonFilter, String filterId) { - mMetadata.mKnownFilters.put(jsonFilter, filterId); - } - - @Override - public Map getFilters() { - return new HashMap<>(mMetadata.mKnownFilters); - } - - @Override - public void setAntivirusServerPublicKey(@Nullable String key) { - mMetadata.mAntivirusServerPublicKey = key; - } - - @Override - @Nullable - public String getAntivirusServerPublicKey() { - return mMetadata.mAntivirusServerPublicKey; - } - - /** - * Update the metrics listener - * - * @param metricsListener the metrics listener - */ - public void setMetricsListener(MetricsListener metricsListener) { - mMetricsListener = metricsListener; - } - - /** - * Get the associated dataHandler - * - * @return the associated dataHandler - */ - protected MXDataHandler getDataHandler() { - return mDataHandler; - } - - /** - * Update the associated dataHandler - * - * @param dataHandler the dataHandler - */ - public void setDataHandler(final MXDataHandler dataHandler) { - mDataHandler = dataHandler; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/store/MXStoreListener.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/store/MXStoreListener.java deleted file mode 100644 index 19de74a9..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/store/MXStoreListener.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2015 OpenMarket 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.matrix.android.internal.legacy.data.store; - -/** - * An default implementation of IMXStoreListener - */ -public class MXStoreListener implements IMXStoreListener { - @Override - public void postProcess(String accountId) { - } - - @Override - public void onStoreReady(String accountId) { - } - - @Override - public void onStoreCorrupted(String accountId, String description) { - } - - @Override - public void onStoreOOM(String accountId, String description) { - } - - @Override - public void onReadReceiptsLoaded(String roomId) { - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/EventTimeline.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/EventTimeline.java deleted file mode 100644 index 97372669..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/EventTimeline.java +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.data.timeline; - -import android.support.annotation.NonNull; - -import im.vector.matrix.android.internal.legacy.data.Room; -import im.vector.matrix.android.internal.legacy.data.RoomState; -import im.vector.matrix.android.internal.legacy.data.store.IMXStore; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.sync.InvitedRoomSync; -import im.vector.matrix.android.internal.legacy.rest.model.sync.RoomSync; - -/** - * A `EventTimeline` instance represents a contiguous sequence of events in a room. - *

- * There are two kinds of timeline: - *

- * - live timelines: they receive live events from the events stream. You can paginate - * backwards but not forwards. - * All (live or backwards) events they receive are stored in the store of the current - * MXSession. - *

- * - past timelines: they start in the past from an `initialEventId`. They are filled - * with events on calls of [MXEventTimeline paginate] in backwards or forwards direction. - * Events are stored in a in-memory store (MXMemoryStore). - */ -public interface EventTimeline { - /** - * Defines that the current timeline is an historical one - * - * @param isHistorical true when the current timeline is an historical one - */ - void setIsHistorical(boolean isHistorical); - - /** - * Returns true if the current timeline is an historical one - */ - boolean isHistorical(); - - /** - * @return the unique identifier - */ - String getTimelineId(); - - /** - * @return the dedicated room - */ - Room getRoom(); - - /** - * @return the used store - */ - IMXStore getStore(); - - /** - * @return the initial event id. - */ - String getInitialEventId(); - - /** - * @return true if this timeline is the live one - */ - boolean isLiveTimeline(); - - /** - * Get whether we are at the end of the message stream - * - * @return true if end has been reached - */ - boolean hasReachedHomeServerForwardsPaginationEnd(); - - /** - * Reset the back state so that future history requests start over from live. - * Must be called when opening a room if interested in history. - */ - void initHistory(); - - /** - * @return The state of the room at the top most recent event of the timeline. - */ - RoomState getState(); - - /** - * Update the state. - * - * @param state the new state. - */ - void setState(RoomState state); - - /** - * Handle the invitation room events - * - * @param invitedRoomSync the invitation room events. - */ - void handleInvitedRoomSync(InvitedRoomSync invitedRoomSync); - - /** - * Manage the joined room events. - * - * @param roomSync the roomSync. - * @param isGlobalInitialSync true if the sync has been triggered by a global initial sync - */ - void handleJoinedRoomSync(@NonNull RoomSync roomSync, boolean isGlobalInitialSync); - - /** - * Store an outgoing event. - * - * @param event the event to store - */ - void storeOutgoingEvent(Event event); - - /** - * Tells if a back pagination can be triggered. - * - * @return true if a back pagination can be triggered. - */ - boolean canBackPaginate(); - - /** - * Request older messages. - * - * @param callback the asynchronous callback - * @return true if request starts - */ - boolean backPaginate(ApiCallback callback); - - /** - * Request older messages. - * - * @param eventCount number of events we want to retrieve - * @param callback callback to implement to be informed that the pagination request has been completed. Can be null. - * @return true if request starts - */ - boolean backPaginate(int eventCount, ApiCallback callback); - - /** - * Request older messages. - * - * @param eventCount number of events we want to retrieve - * @param useCachedOnly to use the cached events list only (i.e no request will be triggered) - * @param callback callback to implement to be informed that the pagination request has been completed. Can be null. - * @return true if request starts - */ - boolean backPaginate(int eventCount, boolean useCachedOnly, ApiCallback callback); - - /** - * Request newer messages. - * - * @param callback callback to implement to be informed that the pagination request has been completed. Can be null. - * @return true if request starts - */ - boolean forwardPaginate(ApiCallback callback); - - /** - * Trigger a pagination in the expected direction. - * - * @param direction the direction. - * @param callback the callback. - * @return true if the operation succeeds - */ - boolean paginate(Direction direction, ApiCallback callback); - - /** - * Cancel any pending pagination requests - */ - void cancelPaginationRequests(); - - /** - * Reset the pagination timeline and start loading the context around its `initialEventId`. - * The retrieved (backwards and forwards) events will be sent to registered listeners. - * - * @param limit the maximum number of messages to get around the initial event. - * @param callback the operation callback - */ - void resetPaginationAroundInitialEvent(int limit, ApiCallback callback); - - /** - * Add an events listener. - * - * @param listener the listener to add. - */ - void addEventTimelineListener(Listener listener); - - /** - * Remove an events listener. - * - * @param listener the listener to remove. - */ - void removeEventTimelineListener(Listener listener); - - /** - * The direction from which an incoming event is considered. - */ - enum Direction { - /** - * Forwards when the event is added to the end of the timeline. - * These events come from the /sync stream or from forwards pagination. - */ - FORWARDS, - - /** - * Backwards when the event is added to the start of the timeline. - * These events come from a back pagination. - */ - BACKWARDS - } - - interface Listener { - - /** - * Call when an event has been handled in the timeline. - * - * @param event the event. - * @param direction the direction. - * @param roomState the room state - */ - void onEvent(Event event, Direction direction, RoomState roomState); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/EventTimelineFactory.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/EventTimelineFactory.java deleted file mode 100644 index 6cbdefab..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/EventTimelineFactory.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.data.timeline; - -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; - -import im.vector.matrix.android.internal.legacy.MXDataHandler; -import im.vector.matrix.android.internal.legacy.data.Room; -import im.vector.matrix.android.internal.legacy.data.store.MXMemoryStore; - -/** - * This factory creates MXEventTimeline instances - */ -public class EventTimelineFactory { - - /** - * Method to create a live timeline associated with the room. - * - * @param dataHandler the dataHandler - * @param room the linked room - * @param roomId the room id - */ - public static EventTimeline liveTimeline(@NonNull final MXDataHandler dataHandler, - @NonNull final Room room, - @NonNull final String roomId) { - return new MXEventTimeline(dataHandler.getStore(roomId), dataHandler, room, roomId, null, true); - } - - /** - * Method to create an in memory timeline for a room. - * - * @param dataHandler the data handler - * @param roomId the room id. - */ - public static EventTimeline inMemoryTimeline(@NonNull final MXDataHandler dataHandler, - @NonNull final String roomId) { - return inMemoryTimeline(dataHandler, roomId, null); - } - - /** - * Method to create a past timeline around an eventId. - * It will create a memory store and a room - * - * @param dataHandler the data handler - * @param roomId the room id - * @param eventId the event id - */ - public static EventTimeline pastTimeline(@NonNull final MXDataHandler dataHandler, - @NonNull final String roomId, - @NonNull final String eventId) { - return inMemoryTimeline(dataHandler, roomId, eventId); - } - - /* ========================================================================================== - * Private - * ========================================================================================== */ - - /** - * Method to create a in memory timeline. - * It will create a memory store and a room - * - * @param dataHandler the data handler - * @param roomId the room id - * @param eventId the event id or null - */ - private static EventTimeline inMemoryTimeline(@NonNull final MXDataHandler dataHandler, - @NonNull final String roomId, - @Nullable final String eventId) { - final MXMemoryStore store = new MXMemoryStore(dataHandler.getCredentials(), null); - final Room room = dataHandler.getRoom(store, roomId, true); - final EventTimeline eventTimeline = new MXEventTimeline(store, dataHandler, room, roomId, eventId, false); - room.setTimeline(eventTimeline); - room.setReadyState(true); - return eventTimeline; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/MXEventTimeline.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/MXEventTimeline.java deleted file mode 100644 index ea4ead5f..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/MXEventTimeline.java +++ /dev/null @@ -1,990 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.data.timeline; - -import android.os.AsyncTask; -import android.os.Looper; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.text.TextUtils; - -import im.vector.matrix.android.internal.legacy.MXDataHandler; -import im.vector.matrix.android.internal.legacy.data.Room; -import im.vector.matrix.android.internal.legacy.data.RoomState; -import im.vector.matrix.android.internal.legacy.data.RoomSummary; -import im.vector.matrix.android.internal.legacy.data.store.IMXStore; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.SimpleApiCallback; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.EventContext; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.rest.model.TokensChunkEvents; -import im.vector.matrix.android.internal.legacy.rest.model.sync.InvitedRoomSync; -import im.vector.matrix.android.internal.legacy.rest.model.sync.RoomSync; -import im.vector.matrix.android.internal.legacy.util.FilterUtil; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * A private implementation of EventTimeline interface. It's not exposed as you don't have to directly instantiate it. - * Should be instantiated through EventTimelineFactory. - */ -class MXEventTimeline implements EventTimeline { - private static final String LOG_TAG = MXEventTimeline.class.getSimpleName(); - - /** - * The initial event id used to initialise the timeline. - * null in case of live timeline. - */ - private String mInitialEventId; - - /** - * Indicate if this timeline is a live one. - */ - private boolean mIsLiveTimeline; - - /** - * The associated room. - */ - private final Room mRoom; - - /** - * the room Id - */ - private String mRoomId; - - /** - * The store. - */ - private IMXStore mStore; - - /** - * MXStore does only back pagination. So, the forward pagination token for - * past timelines is managed locally. - */ - private String mForwardsPaginationToken; - private boolean mHasReachedHomeServerForwardsPaginationEnd; - - /** - * The data handler : used to retrieve data from the store or to trigger REST requests. - */ - private MXDataHandler mDataHandler; - - /** - * Pending request statuses - */ - private boolean mIsBackPaginating = false; - private boolean mIsForwardPaginating = false; - - /** - * true if the back history has been retrieved. - */ - public boolean mCanBackPaginate = true; - - /** - * true if the last back chunck has been received - */ - private boolean mIsLastBackChunk; - - /** - * the server provides a token even for the first room message (which should never change it is the creator message). - * so requestHistory always triggers a remote request which returns an empty json. - * try to avoid such behaviour - */ - private String mBackwardTopToken = "not yet found"; - - // true when the current timeline is an historical one - private boolean mIsHistorical; - - /** - * Unique identifier - */ - private final String mTimelineId = System.currentTimeMillis() + ""; - - /** - * * This class handles storing a live room event in a dedicated store. - */ - private final TimelineEventSaver mTimelineEventSaver; - - /** - * This class is responsible for holding the state and backState of a room timeline - */ - private final TimelineStateHolder mStateHolder; - - /** - * This class handle the timeline event listeners - */ - private final TimelineEventListeners mEventListeners; - - /** - * This class is responsible for handling events coming down from the event stream. - */ - private final TimelineLiveEventHandler mLiveEventHandler; - - /** - * Constructor with package visibility. Creation should be done through EventTimelineFactory - * - * @param store the store associated (in case of past timeline, the store is memory only) - * @param dataHandler the dataHandler - * @param room the room - * @param roomId the room id - * @param eventId the eventId - * @param isLive true if the timeline is a live one - */ - MXEventTimeline(@NonNull final IMXStore store, - @NonNull final MXDataHandler dataHandler, - @NonNull final Room room, - @NonNull final String roomId, - @Nullable final String eventId, - final boolean isLive) { - mIsLiveTimeline = isLive; - mInitialEventId = eventId; - mDataHandler = dataHandler; - mRoom = room; - mRoomId = roomId; - mStore = store; - mEventListeners = new TimelineEventListeners(); - mStateHolder = new TimelineStateHolder(mDataHandler, mStore, roomId); - final StateEventRedactionChecker stateEventRedactionChecker = new StateEventRedactionChecker(this, mStateHolder); - mTimelineEventSaver = new TimelineEventSaver(mStore, mRoom, mStateHolder); - final TimelinePushWorker timelinePushWorker = new TimelinePushWorker(mDataHandler); - mLiveEventHandler = new TimelineLiveEventHandler(this, - mTimelineEventSaver, - stateEventRedactionChecker, - timelinePushWorker, - mStateHolder, - mEventListeners); - } - - /** - * Defines that the current timeline is an historical one - * - * @param isHistorical true when the current timeline is an historical one - */ - @Override - public void setIsHistorical(boolean isHistorical) { - mIsHistorical = isHistorical; - } - - /** - * Returns true if the current timeline is an historical one - */ - @Override - public boolean isHistorical() { - return mIsHistorical; - } - - /* - * @return the unique identifier - */ - @Override - public String getTimelineId() { - return mTimelineId; - } - - /** - * @return the dedicated room - */ - @Override - public Room getRoom() { - return mRoom; - } - - /** - * @return the used store - */ - @Override - public IMXStore getStore() { - return mStore; - } - - /** - * @return the initial event id. - */ - @Override - public String getInitialEventId() { - return mInitialEventId; - } - - /** - * @return true if this timeline is the live one - */ - @Override - public boolean isLiveTimeline() { - return mIsLiveTimeline; - } - - /** - * Get whether we are at the end of the message stream - * - * @return true if end has been reached - */ - @Override - public boolean hasReachedHomeServerForwardsPaginationEnd() { - return mHasReachedHomeServerForwardsPaginationEnd; - } - - - /** - * Reset the back state so that future history requests start over from live. - * Must be called when opening a room if interested in history. - */ - @Override - public void initHistory() { - final RoomState backState = getState().deepCopy(); - setBackState(backState); - mCanBackPaginate = true; - - mIsBackPaginating = false; - mIsForwardPaginating = false; - - // sanity check - if (null != mDataHandler && null != mDataHandler.getDataRetriever()) { - mDataHandler.resetReplayAttackCheckInTimeline(getTimelineId()); - mDataHandler.getDataRetriever().cancelHistoryRequests(mRoomId); - } - } - - /** - * @return The state of the room at the top most recent event of the timeline. - */ - @Override - public RoomState getState() { - return mStateHolder.getState(); - } - - /** - * Update the state. - * - * @param state the new state. - */ - @Override - public void setState(RoomState state) { - mStateHolder.setState(state); - } - - /** - * Update the backState. - * - * @param state the new backState. - */ - private void setBackState(RoomState state) { - mStateHolder.setBackState(state); - } - - /** - * @return the backState. - */ - private RoomState getBackState() { - return mStateHolder.getBackState(); - } - - /** - * Lock over the backPaginate process - * - * @param canBackPaginate the state of the lock (true/false) - */ - protected void setCanBackPaginate(final boolean canBackPaginate) { - mCanBackPaginate = canBackPaginate; - } - - /** - * Make a deep copy or the dedicated state. - * - * @param direction the room state direction to deep copy. - */ - private void deepCopyState(Direction direction) { - mStateHolder.deepCopyState(direction); - } - - /** - * Process a state event to keep the internal live and back states up to date. - * - * @param event the state event - * @param direction the direction; ie. forwards for live state, backwards for back state - * @return true if the event has been processed. - */ - private boolean processStateEvent(Event event, Direction direction) { - return mStateHolder.processStateEvent(event, direction); - } - - /** - * Handle the invitation room events - * - * @param invitedRoomSync the invitation room events. - */ - @Override - public void handleInvitedRoomSync(InvitedRoomSync invitedRoomSync) { - final TimelineInvitedRoomSyncHandler invitedRoomSyncHandler = new TimelineInvitedRoomSyncHandler(mRoom, mLiveEventHandler, invitedRoomSync); - invitedRoomSyncHandler.handle(); - } - - /** - * Manage the joined room events. - * - * @param roomSync the roomSync. - * @param isGlobalInitialSync true if the sync has been triggered by a global initial sync - */ - @Override - public void handleJoinedRoomSync(@NonNull final RoomSync roomSync, final boolean isGlobalInitialSync) { - final TimelineJoinRoomSyncHandler joinRoomSyncHandler = new TimelineJoinRoomSyncHandler(this, - roomSync, - mStateHolder, - mLiveEventHandler, - isGlobalInitialSync); - joinRoomSyncHandler.handle(); - } - - /** - * Store an outgoing event. - * - * @param event the event to store - */ - @Override - public void storeOutgoingEvent(Event event) { - if (mIsLiveTimeline) { - storeEvent(event); - } - } - - /** - * Store the event and update the dedicated room summary - * - * @param event the event to store - */ - private void storeEvent(Event event) { - mTimelineEventSaver.storeEvent(event); - } - - //================================================================================ - // History request - //================================================================================ - - private static final int MAX_EVENT_COUNT_PER_PAGINATION = 30; - - // the storage events are buffered to provide a small bunch of events - // the storage can provide a big bunch which slows down the UI. - public class SnapshotEvent { - public final Event mEvent; - public final RoomState mState; - - public SnapshotEvent(Event event, RoomState state) { - mEvent = event; - mState = state; - } - } - - // avoid adding to many events - // the room history request can provide more than expected event. - private final List mSnapshotEvents = new ArrayList<>(); - - /** - * Send MAX_EVENT_COUNT_PER_PAGINATION events to the caller. - * - * @param maxEventCount the max event count - * @param callback the callback. - */ - private void manageBackEvents(int maxEventCount, final ApiCallback callback) { - // check if the SDK was not logged out - if (!mDataHandler.isAlive()) { - Log.d(LOG_TAG, "manageEvents : mDataHandler is not anymore active."); - - return; - } - - int count = Math.min(mSnapshotEvents.size(), maxEventCount); - - Event latestSupportedEvent = null; - - for (int i = 0; i < count; i++) { - SnapshotEvent snapshotedEvent = mSnapshotEvents.get(0); - - // in some cases, there is no displayed summary - // https://github.com/vector-im/vector-android/pull/354 - if (null == latestSupportedEvent && RoomSummary.isSupportedEvent(snapshotedEvent.mEvent)) { - latestSupportedEvent = snapshotedEvent.mEvent; - } - - mSnapshotEvents.remove(0); - mEventListeners.onEvent(snapshotedEvent.mEvent, Direction.BACKWARDS, snapshotedEvent.mState); - } - - // https://github.com/vector-im/vector-android/pull/354 - // defines a new summary if the known is not supported - RoomSummary summary = mStore.getSummary(mRoomId); - - if (null != latestSupportedEvent && (null == summary || !RoomSummary.isSupportedEvent(summary.getLatestReceivedEvent()))) { - mStore.storeSummary(new RoomSummary(null, latestSupportedEvent, getState(), mDataHandler.getUserId())); - } - - Log.d(LOG_TAG, "manageEvents : commit"); - mStore.commit(); - - if (mSnapshotEvents.size() < MAX_EVENT_COUNT_PER_PAGINATION && mIsLastBackChunk) { - mCanBackPaginate = false; - } - mIsBackPaginating = false; - if (callback != null) { - try { - callback.onSuccess(count); - } catch (Exception e) { - Log.e(LOG_TAG, "requestHistory exception " + e.getMessage(), e); - } - } - } - - /** - * Add some events in a dedicated direction. - * - * @param events the events list - * @param stateEvents the received state events (in case of lazy loading of room members) - * @param direction the direction - */ - private void addPaginationEvents(List events, - @Nullable List stateEvents, - Direction direction) { - RoomSummary summary = mStore.getSummary(mRoomId); - boolean shouldCommitStore = false; - - // Process additional state events (this happens in case of lazy loading) - if (stateEvents != null) { - for (Event stateEvent : stateEvents) { - if (direction == Direction.BACKWARDS) { - // Enrich the timeline root state with the additional state events observed during back pagination - processStateEvent(stateEvent, Direction.FORWARDS); - } - - processStateEvent(stateEvent, direction); - } - } - - // the backward events have a dedicated management to avoid providing too many events for each request - for (Event event : events) { - boolean processedEvent = true; - - if (event.stateKey != null) { - deepCopyState(direction); - processedEvent = processStateEvent(event, direction); - } - - // Decrypt event if necessary - mDataHandler.decryptEvent(event, getTimelineId()); - - if (processedEvent) { - // warn the listener only if the message is processed. - // it should avoid duplicated events. - if (direction == Direction.BACKWARDS) { - if (mIsLiveTimeline) { - // update the summary is the event has been received after the oldest known event - // it might happen after a timeline update (hole in the chat history) - if (null != summary - && (null == summary.getLatestReceivedEvent() - || event.isValidOriginServerTs() - && summary.getLatestReceivedEvent().originServerTs < event.originServerTs - && RoomSummary.isSupportedEvent(event))) { - summary.setLatestReceivedEvent(event, getState()); - mStore.storeSummary(summary); - shouldCommitStore = true; - } - } - mSnapshotEvents.add(new SnapshotEvent(event, getBackState())); - // onEvent will be called in manageBackEvents - } - } - } - - if (shouldCommitStore) { - mStore.commit(); - } - } - - /** - * Add some events in a dedicated direction. - * - * @param events the events list - * @param stateEvents the received state events (in case of lazy loading of room members) - * @param direction the direction - * @param callback the callback. - */ - private void addPaginationEvents(final List events, - @Nullable final List stateEvents, - final Direction direction, - final ApiCallback callback) { - AsyncTask task = new AsyncTask() { - @Override - protected Void doInBackground(Void... params) { - addPaginationEvents(events, stateEvents, direction); - return null; - } - - @Override - protected void onPostExecute(Void args) { - if (direction == Direction.BACKWARDS) { - manageBackEvents(MAX_EVENT_COUNT_PER_PAGINATION, callback); - } else { - for (Event event : events) { - mEventListeners.onEvent(event, Direction.FORWARDS, getState()); - } - - if (null != callback) { - callback.onSuccess(events.size()); - } - } - } - }; - - try { - task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } catch (final Exception e) { - Log.e(LOG_TAG, "## addPaginationEvents() failed " + e.getMessage(), e); - task.cancel(true); - - new android.os.Handler(Looper.getMainLooper()).post(new Runnable() { - @Override - public void run() { - if (null != callback) { - callback.onUnexpectedError(e); - } - } - }); - } - } - - /** - * Tells if a back pagination can be triggered. - * - * @return true if a back pagination can be triggered. - */ - @Override - public boolean canBackPaginate() { - // One at a time please - return !mIsBackPaginating - // history_visibility flag management - && getState().canBackPaginate(mRoom.isJoined(), mRoom.isInvited()) - // If we have already reached the end of history - && mCanBackPaginate - // If the room is not finished being set up - && mRoom.isReady(); - } - - /** - * Request older messages. - * - * @param callback the asynchronous callback - * @return true if request starts - */ - @Override - public boolean backPaginate(final ApiCallback callback) { - return backPaginate(MAX_EVENT_COUNT_PER_PAGINATION, callback); - } - - /** - * Request older messages. - * - * @param eventCount number of events we want to retrieve - * @param callback callback to implement to be informed that the pagination request has been completed. Can be null. - * @return true if request starts - */ - @Override - public boolean backPaginate(final int eventCount, final ApiCallback callback) { - return backPaginate(eventCount, false, callback); - } - - /** - * Request older messages. - * - * @param eventCount number of events we want to retrieve - * @param useCachedOnly to use the cached events list only (i.e no request will be triggered) - * @param callback callback to implement to be informed that the pagination request has been completed. Can be null. - * @return true if request starts - */ - @Override - public boolean backPaginate(final int eventCount, final boolean useCachedOnly, final ApiCallback callback) { - if (!canBackPaginate()) { - Log.d(LOG_TAG, "cannot requestHistory " + mIsBackPaginating + " " + !getState().canBackPaginate(mRoom.isJoined(), mRoom.isInvited()) - + " " + !mCanBackPaginate + " " + !mRoom.isReady()); - return false; - } - - Log.d(LOG_TAG, "backPaginate starts"); - - // restart the pagination - if (null == getBackState().getToken()) { - mSnapshotEvents.clear(); - } - - final String fromBackToken = getBackState().getToken(); - - mIsBackPaginating = true; - - // enough buffered data - if (useCachedOnly - || mSnapshotEvents.size() >= eventCount - || TextUtils.equals(fromBackToken, mBackwardTopToken) - || TextUtils.equals(fromBackToken, Event.PAGINATE_BACK_TOKEN_END)) { - - mIsLastBackChunk = TextUtils.equals(fromBackToken, mBackwardTopToken) || TextUtils.equals(fromBackToken, Event.PAGINATE_BACK_TOKEN_END); - - final android.os.Handler handler = new android.os.Handler(Looper.getMainLooper()); - final int maxEventsCount; - - if (useCachedOnly) { - Log.d(LOG_TAG, "backPaginate : load " + mSnapshotEvents.size() + "cached events list"); - maxEventsCount = Math.min(mSnapshotEvents.size(), eventCount); - } else if (mSnapshotEvents.size() >= eventCount) { - Log.d(LOG_TAG, "backPaginate : the events are already loaded."); - maxEventsCount = eventCount; - } else { - Log.d(LOG_TAG, "backPaginate : reach the history top"); - maxEventsCount = eventCount; - } - - // call the callback with a delay - // to reproduce the same behaviour as a network request. - Runnable r = new Runnable() { - @Override - public void run() { - handler.postDelayed(new Runnable() { - public void run() { - manageBackEvents(maxEventsCount, callback); - } - }, 0); - } - }; - - Thread t = new Thread(r); - t.start(); - - return true; - } - - mDataHandler.getDataRetriever().backPaginate(mStore, mRoomId, getBackState().getToken(), eventCount, mDataHandler.isLazyLoadingEnabled(), - new SimpleApiCallback(callback) { - @Override - public void onSuccess(TokensChunkEvents response) { - if (mDataHandler.isAlive()) { - - if (null != response.chunk) { - Log.d(LOG_TAG, "backPaginate : " + response.chunk.size() + " events are retrieved."); - } else { - Log.d(LOG_TAG, "backPaginate : there is no event"); - } - - mIsLastBackChunk = null != response.chunk - && 0 == response.chunk.size() - && TextUtils.equals(response.end, response.start) - || null == response.end; - - if (mIsLastBackChunk && null != response.end) { - // save its token to avoid useless request - mBackwardTopToken = fromBackToken; - } else { - // the server returns a null pagination token when there is no more available data - if (null == response.end) { - getBackState().setToken(Event.PAGINATE_BACK_TOKEN_END); - } else { - getBackState().setToken(response.end); - } - } - - addPaginationEvents(null == response.chunk ? new ArrayList() : response.chunk, - response.stateEvents, - Direction.BACKWARDS, - callback); - - } else { - Log.d(LOG_TAG, "mDataHandler is not active."); - } - } - - @Override - public void onMatrixError(MatrixError e) { - Log.d(LOG_TAG, "backPaginate onMatrixError"); - - // When we've retrieved all the messages from a room, the pagination token is some invalid value - if (MatrixError.UNKNOWN.equals(e.errcode)) { - mCanBackPaginate = false; - } - mIsBackPaginating = false; - - super.onMatrixError(e); - } - - @Override - public void onNetworkError(Exception e) { - Log.d(LOG_TAG, "backPaginate onNetworkError"); - - mIsBackPaginating = false; - - super.onNetworkError(e); - } - - @Override - public void onUnexpectedError(Exception e) { - Log.d(LOG_TAG, "backPaginate onUnexpectedError"); - - mIsBackPaginating = false; - - super.onUnexpectedError(e); - } - }); - - return true; - } - - /** - * Request newer messages. - * - * @param callback callback to implement to be informed that the pagination request has been completed. Can be null. - * @return true if request starts - */ - @Override - public boolean forwardPaginate(final ApiCallback callback) { - if (mIsLiveTimeline) { - Log.d(LOG_TAG, "Cannot forward paginate on Live timeline"); - return false; - } - - if (mIsForwardPaginating || mHasReachedHomeServerForwardsPaginationEnd) { - Log.d(LOG_TAG, "forwardPaginate " + mIsForwardPaginating - + " mHasReachedHomeServerForwardsPaginationEnd " + mHasReachedHomeServerForwardsPaginationEnd); - return false; - } - - mIsForwardPaginating = true; - - mDataHandler.getDataRetriever().paginate(mStore, mRoomId, mForwardsPaginationToken, Direction.FORWARDS, mDataHandler.isLazyLoadingEnabled(), - new SimpleApiCallback(callback) { - @Override - public void onSuccess(TokensChunkEvents response) { - if (mDataHandler.isAlive()) { - Log.d(LOG_TAG, "forwardPaginate : " + response.chunk.size() + " are retrieved."); - - mHasReachedHomeServerForwardsPaginationEnd = 0 == response.chunk.size() && TextUtils.equals(response.end, response.start); - mForwardsPaginationToken = response.end; - - addPaginationEvents(response.chunk, - response.stateEvents, - Direction.FORWARDS, - callback); - - mIsForwardPaginating = false; - } else { - Log.d(LOG_TAG, "mDataHandler is not active."); - } - } - - @Override - public void onMatrixError(MatrixError e) { - mIsForwardPaginating = false; - - super.onMatrixError(e); - } - - @Override - public void onNetworkError(Exception e) { - mIsForwardPaginating = false; - - super.onNetworkError(e); - } - - @Override - public void onUnexpectedError(Exception e) { - mIsForwardPaginating = false; - - super.onUnexpectedError(e); - } - }); - - return true; - } - - /** - * Trigger a pagination in the expected direction. - * - * @param direction the direction. - * @param callback the callback. - * @return true if the operation succeeds - */ - @Override - public boolean paginate(Direction direction, final ApiCallback callback) { - if (Direction.BACKWARDS == direction) { - return backPaginate(callback); - } else { - return forwardPaginate(callback); - } - } - - /** - * Cancel any pending pagination requests - */ - @Override - public void cancelPaginationRequests() { - mDataHandler.getDataRetriever().cancelHistoryRequests(mRoomId); - mIsBackPaginating = false; - mIsForwardPaginating = false; - } - - //============================================================================================================== - // pagination methods - //============================================================================================================== - - /** - * Reset the pagination timeline and start loading the context around its `initialEventId`. - * The retrieved (backwards and forwards) events will be sent to registered listeners. - * - * @param limit the maximum number of messages to get around the initial event. - * @param callback the operation callback - */ - @Override - public void resetPaginationAroundInitialEvent(final int limit, final ApiCallback callback) { - // Reset the store - mStore.deleteRoomData(mRoomId); - - mDataHandler.resetReplayAttackCheckInTimeline(getTimelineId()); - - mForwardsPaginationToken = null; - mHasReachedHomeServerForwardsPaginationEnd = false; - - mDataHandler.getDataRetriever() - .getRoomsRestClient() - .getContextOfEvent(mRoomId, mInitialEventId, limit, FilterUtil.createRoomEventFilter(mDataHandler.isLazyLoadingEnabled()), - new SimpleApiCallback(callback) { - @Override - public void onSuccess(final EventContext eventContext) { - - AsyncTask task = new AsyncTask() { - @Override - protected Void doInBackground(Void... params) { - // the state is the one after the latest event of the chunk i.e. the last message of eventContext.eventsAfter - for (Event event : eventContext.state) { - processStateEvent(event, Direction.FORWARDS); - } - - // init the room states - initHistory(); - - // build the events list - List events = new ArrayList<>(); - - Collections.reverse(eventContext.eventsAfter); - events.addAll(eventContext.eventsAfter); - events.add(eventContext.event); - events.addAll(eventContext.eventsBefore); - - // add events after - addPaginationEvents(events, null, Direction.BACKWARDS); - - return null; - } - - @Override - protected void onPostExecute(Void args) { - // create dummy forward events list - // to center the selected event id - // else if might be out of screen - List nextSnapshotEvents = new ArrayList<>(mSnapshotEvents.subList(0, (mSnapshotEvents.size() + 1) / 2)); - - // put in the right order - Collections.reverse(nextSnapshotEvents); - - // send them one by one - for (SnapshotEvent snapshotEvent : nextSnapshotEvents) { - mSnapshotEvents.remove(snapshotEvent); - mEventListeners.onEvent(snapshotEvent.mEvent, Direction.FORWARDS, snapshotEvent.mState); - } - - // init the tokens - getBackState().setToken(eventContext.start); - mForwardsPaginationToken = eventContext.end; - - // send the back events to complete pagination - manageBackEvents(MAX_EVENT_COUNT_PER_PAGINATION, new ApiCallback() { - @Override - public void onSuccess(Integer info) { - Log.d(LOG_TAG, "addPaginationEvents succeeds"); - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "addPaginationEvents failed " + e.getMessage(), e); - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "addPaginationEvents failed " + e.getMessage()); - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "addPaginationEvents failed " + e.getMessage(), e); - } - }); - - // everything is done - callback.onSuccess(null); - } - }; - - try { - task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } catch (final Exception e) { - Log.e(LOG_TAG, "## resetPaginationAroundInitialEvent() failed " + e.getMessage(), e); - task.cancel(true); - - new android.os.Handler(Looper.getMainLooper()).post(new Runnable() { - @Override - public void run() { - if (callback != null) { - callback.onUnexpectedError(e); - } - } - }); - } - } - }); - } - - //============================================================================================================== - // onEvent listener management. - //============================================================================================================== - - /** - * Add an events listener. - * - * @param listener the listener to add. - */ - @Override - public void addEventTimelineListener(@Nullable final Listener listener) { - mEventListeners.add(listener); - } - - /** - * Remove an events listener. - * - * @param listener the listener to remove. - */ - @Override - public void removeEventTimelineListener(@Nullable final Listener listener) { - mEventListeners.remove(listener); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/StateEventRedactionChecker.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/StateEventRedactionChecker.java deleted file mode 100644 index f0ac3bf5..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/StateEventRedactionChecker.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.data.timeline; - -import android.support.annotation.NonNull; -import android.text.TextUtils; - -import im.vector.matrix.android.internal.legacy.MXDataHandler; -import im.vector.matrix.android.internal.legacy.data.Room; -import im.vector.matrix.android.internal.legacy.data.RoomState; -import im.vector.matrix.android.internal.legacy.data.store.IMXStore; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.SimpleApiCallback; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.rest.model.RoomMember; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.util.List; - -import javax.annotation.Nonnull; - -/** - * This class is responsible of checking state events redaction. - */ -class StateEventRedactionChecker { - - private static final String LOG_TAG = StateEventRedactionChecker.class.getSimpleName(); - private final EventTimeline mEventTimeline; - private final TimelineStateHolder mTimelineStateHolder; - - StateEventRedactionChecker(@NonNull final EventTimeline eventTimeline, - @NonNull final TimelineStateHolder timelineStateHolder) { - mEventTimeline = eventTimeline; - mTimelineStateHolder = timelineStateHolder; - } - - /** - * Redaction of a state event might require to reload the timeline - * because the room states has to be updated. - * - * @param redactionEvent the redaction event - */ - public void checkStateEventRedaction(@NonNull final Event redactionEvent) { - final IMXStore store = mEventTimeline.getStore(); - final Room room = mEventTimeline.getRoom(); - final MXDataHandler dataHandler = room.getDataHandler(); - final String roomId = room.getRoomId(); - final String eventId = redactionEvent.getRedactedEventId(); - final RoomState state = mTimelineStateHolder.getState(); - Log.d(LOG_TAG, "checkStateEventRedaction of event " + eventId); - // check if the state events is locally known - state.getStateEvents(store, null, new SimpleApiCallback>() { - @Override - public void onSuccess(List stateEvents) { - - // Check whether the current room state depends on this redacted event. - boolean isFound = false; - for (int index = 0; index < stateEvents.size(); index++) { - Event stateEvent = stateEvents.get(index); - - if (TextUtils.equals(stateEvent.eventId, eventId)) { - - Log.d(LOG_TAG, "checkStateEventRedaction: the current room state has been modified by the event redaction"); - - // remove expected keys - stateEvent.prune(redactionEvent); - stateEvents.set(index, stateEvent); - // digest the updated state - mTimelineStateHolder.processStateEvent(stateEvent, EventTimeline.Direction.FORWARDS); - isFound = true; - break; - } - } - - if (!isFound) { - // Else try to find the redacted event among members which - // are stored apart from other state events - - // Reason: The membership events are not anymore stored in the application store - // until we have found a way to improve the way they are stored. - // It used to have many out of memory errors because they are too many stored small memory objects. - // see https://github.com/matrix-org/matrix-android-sdk/issues/196 - - // Note: if lazy loading is on, getMemberByEventId() can return null, but it is ok, because we just want to update our cache - RoomMember member = state.getMemberByEventId(eventId); - if (member != null) { - Log.d(LOG_TAG, "checkStateEventRedaction: the current room members list has been modified by the event redaction"); - - // the android SDK does not store stock member events but a representation of them, RoomMember. - // Prune this representation - member.prune(); - - isFound = true; - } - } - - if (isFound) { - store.storeLiveStateForRoom(roomId); - // warn that there was a flush - mEventTimeline.initHistory(); - dataHandler.onRoomFlush(roomId); - } else { - Log.d(LOG_TAG, "checkStateEventRedaction: the redacted event is unknown. Fetch it from the homeserver"); - checkStateEventRedactionWithHomeserver(dataHandler, roomId, eventId); - } - } - }); - } - - /** - * Check with the HS whether the redacted event impacts the room data we have locally. - * If yes, local data must be pruned. - * - * @param eventId the redacted event id - */ - private void checkStateEventRedactionWithHomeserver(@Nonnull final MXDataHandler dataHandler, - @Nonnull final String roomId, - @Nonnull final String eventId) { - Log.d(LOG_TAG, "checkStateEventRedactionWithHomeserver on event Id " + eventId); - - // We need to figure out if this redacted event is a room state in the past. - // If yes, we must prune the `prev_content` of the state event that replaced it. - // Indeed, redacted information shouldn't spontaneously appear when you backpaginate... - // TODO: This is no more implemented (see https://github.com/vector-im/riot-ios/issues/443). - // The previous implementation based on a room initial sync was too heavy server side - // and has been removed. - if (!TextUtils.isEmpty(eventId)) { - Log.d(LOG_TAG, "checkStateEventRedactionWithHomeserver : retrieving the event"); - dataHandler.getDataRetriever().getRoomsRestClient().getEvent(roomId, eventId, new ApiCallback() { - @Override - public void onSuccess(Event event) { - if (null != event && null != event.stateKey) { - Log.d(LOG_TAG, "checkStateEventRedactionWithHomeserver : the redacted event is a state event in the past." + - " TODO: prune prev_content of the new state event"); - - } else { - Log.d(LOG_TAG, "checkStateEventRedactionWithHomeserver : the redacted event is a not state event -> job is done"); - } - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "checkStateEventRedactionWithHomeserver : failed to retrieved the redacted event: onNetworkError " + e.getMessage(), e); - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "checkStateEventRedactionWithHomeserver : failed to retrieved the redacted event: onNetworkError " + e.getMessage()); - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "checkStateEventRedactionWithHomeserver : failed to retrieved the redacted event: onNetworkError " + e.getMessage(), e); - } - }); - } - } - - -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/TimelineEventListeners.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/TimelineEventListeners.java deleted file mode 100644 index ed5c843b..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/TimelineEventListeners.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.data.timeline; - -import android.os.Handler; -import android.os.Looper; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; - -import im.vector.matrix.android.internal.legacy.data.RoomState; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.util.ArrayList; -import java.util.List; - -/** - * Handle the timeline event listeners - * Is responsible for dispatching events - */ -class TimelineEventListeners { - - private static final String LOG_TAG = TimelineEventListeners.class.getSimpleName(); - - // The inner listeners - private final List mListeners = new ArrayList<>(); - - /** - * Add an events listener. - * - * @param listener the listener to add. - */ - public void add(@Nullable final EventTimeline.Listener listener) { - if (listener != null) { - synchronized (this) { - if (!mListeners.contains(listener)) { - mListeners.add(listener); - } - } - } - } - - /** - * Remove an events listener. - * - * @param listener the listener to remove. - */ - public void remove(@Nullable final EventTimeline.Listener listener) { - if (null != listener) { - synchronized (this) { - mListeners.remove(listener); - } - } - } - - /** - * Dispatch the onEvent callback. - * - * @param event the event. - * @param direction the direction. - * @param roomState the roomState. - */ - public void onEvent(@NonNull final Event event, - @NonNull final EventTimeline.Direction direction, - @NonNull final RoomState roomState) { - // ensure that the listeners are called in the UI thread - if (Looper.getMainLooper().getThread() == Thread.currentThread()) { - final List listeners; - synchronized (this) { - listeners = new ArrayList<>(mListeners); - } - for (EventTimeline.Listener listener : listeners) { - try { - listener.onEvent(event, direction, roomState); - } catch (Exception e) { - Log.e(LOG_TAG, "EventTimeline.onEvent " + listener + " crashes " + e.getMessage(), e); - } - } - } else { - final Handler handler = new Handler(Looper.getMainLooper()); - handler.post(new Runnable() { - @Override - public void run() { - onEvent(event, direction, roomState); - } - }); - } - } - - -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/TimelineEventSaver.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/TimelineEventSaver.java deleted file mode 100644 index 35b6e1ac..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/TimelineEventSaver.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.data.timeline; - -import android.support.annotation.NonNull; - -import im.vector.matrix.android.internal.legacy.MXDataHandler; -import im.vector.matrix.android.internal.legacy.data.Room; -import im.vector.matrix.android.internal.legacy.data.RoomState; -import im.vector.matrix.android.internal.legacy.data.RoomSummary; -import im.vector.matrix.android.internal.legacy.data.store.IMXStore; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.ReceiptData; - -/** - * This class handles storing a live room event in a dedicated store. - */ -class TimelineEventSaver { - - private final IMXStore mStore; - private final Room mRoom; - private final TimelineStateHolder mTimelineStateHolder; - - TimelineEventSaver(@NonNull final IMXStore store, - @NonNull final Room room, - @NonNull final TimelineStateHolder timelineStateHolder) { - mStore = store; - mRoom = room; - mTimelineStateHolder = timelineStateHolder; - } - - /** - * * Store a live room event. - * - * @param event the event to be stored. - */ - - public void storeEvent(@NonNull final Event event) { - final MXDataHandler dataHandler = mRoom.getDataHandler(); - final String myUserId = dataHandler.getCredentials().getUserId(); - - // create dummy read receipt for any incoming event - // to avoid not synchronized read receipt and event - if (event.getSender() != null && event.eventId != null) { - mRoom.handleReceiptData(new ReceiptData(event.getSender(), event.eventId, event.originServerTs)); - } - mStore.storeLiveRoomEvent(event); - if (RoomSummary.isSupportedEvent(event)) { - final RoomState roomState = mTimelineStateHolder.getState(); - RoomSummary summary = mStore.getSummary(event.roomId); - if (summary == null) { - summary = new RoomSummary(summary, event, roomState, myUserId); - } else { - summary.setLatestReceivedEvent(event, roomState); - } - mStore.storeSummary(summary); - } - } - -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/TimelineInvitedRoomSyncHandler.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/TimelineInvitedRoomSyncHandler.java deleted file mode 100644 index e70c9a8d..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/TimelineInvitedRoomSyncHandler.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.data.timeline; - -import android.support.annotation.NonNull; - -import im.vector.matrix.android.internal.legacy.data.Room; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.sync.InvitedRoomSync; - -import javax.annotation.Nullable; - -/** - * This class is responsible for handling the invitation room events from the SyncResponse - */ -class TimelineInvitedRoomSyncHandler { - - private final Room mRoom; - private final TimelineLiveEventHandler mLiveEventHandler; - private final InvitedRoomSync mInvitedRoomSync; - - TimelineInvitedRoomSyncHandler(@NonNull final Room room, - @NonNull final TimelineLiveEventHandler liveEventHandler, - @Nullable final InvitedRoomSync invitedRoomSync) { - mRoom = room; - mLiveEventHandler = liveEventHandler; - mInvitedRoomSync = invitedRoomSync; - } - - /** - * Handle the invitation room events - */ - public void handle() { - // Handle the state events as live events (the room state will be updated, and the listeners (if any) will be notified). - if (mInvitedRoomSync != null && mInvitedRoomSync.inviteState != null && mInvitedRoomSync.inviteState.events != null) { - final String roomId = mRoom.getRoomId(); - - for (Event event : mInvitedRoomSync.inviteState.events) { - // Add a fake event id if none in order to be able to store the event - if (event.eventId == null) { - event.eventId = roomId + "-" + System.currentTimeMillis() + "-" + event.hashCode(); - } - - // The roomId is not defined. - event.roomId = roomId; - mLiveEventHandler.handleLiveEvent(event, false, true); - } - // The room related to the pending invite can be considered as ready from now - mRoom.setReadyState(true); - } - } - - -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/TimelineJoinRoomSyncHandler.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/TimelineJoinRoomSyncHandler.java deleted file mode 100644 index 4a2d3b7b..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/TimelineJoinRoomSyncHandler.java +++ /dev/null @@ -1,298 +0,0 @@ -package im.vector.matrix.android.internal.legacy.data.timeline; - -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.text.TextUtils; - -import im.vector.matrix.android.internal.legacy.MXDataHandler; -import im.vector.matrix.android.internal.legacy.data.Room; -import im.vector.matrix.android.internal.legacy.data.RoomState; -import im.vector.matrix.android.internal.legacy.data.RoomSummary; -import im.vector.matrix.android.internal.legacy.data.store.IMXStore; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.RoomMember; -import im.vector.matrix.android.internal.legacy.rest.model.sync.RoomSync; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * This class is responsible for handling a Join RoomSync - */ -class TimelineJoinRoomSyncHandler { - - private static final String LOG_TAG = TimelineJoinRoomSyncHandler.class.getSimpleName(); - - private final MXEventTimeline mEventTimeline; - private final RoomSync mRoomSync; - private final TimelineStateHolder mTimelineStateHolder; - private final TimelineLiveEventHandler mTimelineLiveEventHandler; - private final boolean mIsGlobalInitialSync; - - TimelineJoinRoomSyncHandler(@NonNull final MXEventTimeline eventTimeline, - @NonNull final RoomSync roomSync, - @NonNull final TimelineStateHolder timelineStateHolder, - @NonNull final TimelineLiveEventHandler timelineLiveEventHandler, - final boolean isGlobalInitialSync) { - mEventTimeline = eventTimeline; - mRoomSync = roomSync; - mTimelineStateHolder = timelineStateHolder; - mTimelineLiveEventHandler = timelineLiveEventHandler; - mIsGlobalInitialSync = isGlobalInitialSync; - } - - - public void handle() { - final IMXStore store = mEventTimeline.getStore(); - final Room room = mEventTimeline.getRoom(); - final MXDataHandler dataHandler = room.getDataHandler(); - final String roomId = room.getRoomId(); - final String myUserId = dataHandler.getMyUser().user_id; - final RoomMember selfMember = mTimelineStateHolder.getState().getMember(myUserId); - final RoomSummary currentSummary = store.getSummary(roomId); - - final String membership = selfMember != null ? selfMember.membership : null; - final boolean isRoomInitialSync = membership == null || TextUtils.equals(membership, RoomMember.MEMBERSHIP_INVITE); - - // Check whether the room was pending on an invitation. - if (RoomMember.MEMBERSHIP_INVITE.equals(membership)) { - // Reset the storage of this room. An initial sync of the room will be done with the provided 'roomSync'. - cleanInvitedRoom(store, roomId); - } - if (mRoomSync.state != null && mRoomSync.state.events != null && mRoomSync.state.events.size() > 0) { - handleRoomSyncState(room, store, isRoomInitialSync); - } - // Handle now timeline.events, the room state is updated during this step too (Note: timeline events are in chronological order) - if (mRoomSync.timeline != null) { - handleRoomSyncTimeline(store, myUserId, roomId, currentSummary, isRoomInitialSync); - } - if (isRoomInitialSync) { - // any request history can be triggered by now. - room.setReadyState(true); - } else if (mRoomSync.timeline != null && mRoomSync.timeline.limited) { - // Finalize initial sync - // The room has been synced with a limited timeline - dataHandler.onRoomFlush(roomId); - } - // the EventTimeLine is used when displaying a room preview - // so, the following items should only be called when it is a live one. - if (mEventTimeline.isLiveTimeline()) { - handleLiveTimeline(dataHandler, store, roomId, myUserId, currentSummary); - } - } - - private void handleRoomSyncState(@NonNull final Room room, - @NonNull final IMXStore store, - final boolean isRoomInitialSync) { - if (isRoomInitialSync) { - Log.d(LOG_TAG, "##" + mRoomSync.state.events.size() + " events " - + "for room " + room.getRoomId() - + "in store " + store - ); - } - - // Build/Update first the room state corresponding to the 'start' of the timeline. - // Note: We consider it is not required to clone the existing room state here, because no notification is posted for these events. - if (room.getDataHandler().isAlive()) { - for (Event event : mRoomSync.state.events) { - try { - mTimelineStateHolder.processStateEvent(event, EventTimeline.Direction.FORWARDS); - } catch (Exception e) { - Log.e(LOG_TAG, "processStateEvent failed " + e.getMessage(), e); - } - } - - room.setReadyState(true); - } else { - Log.e(LOG_TAG, "## mDataHandler.isAlive() is false"); - } - // if it is an initial sync, the live state is initialized here - // so the back state must also be initialized - if (isRoomInitialSync) { - final RoomState state = mTimelineStateHolder.getState(); - Log.d(LOG_TAG, "## handleJoinedRoomSync() : retrieve X " + state.getLoadedMembers().size() + " members for room " + room.getRoomId()); - mTimelineStateHolder.setBackState(state.deepCopy()); - } - } - - private void cleanInvitedRoom(@NonNull final IMXStore store, - @NonNull final String roomId) { - Log.d(LOG_TAG, "clean invited room from the store " + roomId); - store.deleteRoomData(roomId); - mTimelineStateHolder.clear(); - } - - private void handleRoomSyncTimeline(@NonNull final IMXStore store, - @NonNull final String myUserId, - @NonNull final String roomId, - @Nullable final RoomSummary currentSummary, - final boolean isRoomInitialSync) { - if (mRoomSync.timeline.limited) { - if (!isRoomInitialSync) { - final RoomState state = mTimelineStateHolder.getState(); - // There is a gap between known events and received events in this incremental sync. - // define a summary if some messages are left - // the unsent messages are often displayed messages. - final Event oldestEvent = store.getOldestEvent(roomId); - // Flush the existing messages for this room by keeping state events. - store.deleteAllRoomMessages(roomId, true); - if (oldestEvent != null) { - if (RoomSummary.isSupportedEvent(oldestEvent)) { - if (currentSummary != null) { - currentSummary.setLatestReceivedEvent(oldestEvent, state); - store.storeSummary(currentSummary); - } else { - store.storeSummary(new RoomSummary(null, oldestEvent, state, myUserId)); - } - } - } - // Force a fetch of the loaded members the next time they will be requested - state.forceMembersRequest(); - } - - // if the prev batch is set to null - // it implies there is no more data on server side. - if (mRoomSync.timeline.prevBatch == null) { - mRoomSync.timeline.prevBatch = Event.PAGINATE_BACK_TOKEN_END; - } - - // In case of limited timeline, update token where to start back pagination - store.storeBackToken(roomId, mRoomSync.timeline.prevBatch); - // reset the state back token - // because it does not make anymore sense - // by setting at null, the events cache will be cleared when a requesthistory will be called - mTimelineStateHolder.getBackState().setToken(null); - // reset the back paginate lock - mEventTimeline.setCanBackPaginate(true); - } - - // any event ? - if (mRoomSync.timeline.events != null && !mRoomSync.timeline.events.isEmpty()) { - final List events = mRoomSync.timeline.events; - // save the back token - events.get(0).mToken = mRoomSync.timeline.prevBatch; - - // Here the events are handled in forward direction (see [handleLiveEvent:]). - // They will be added at the end of the stored events, so we keep the chronological order. - for (Event event : events) { - // the roomId is not defined. - event.roomId = roomId; - try { - boolean isLimited = mRoomSync.timeline != null && mRoomSync.timeline.limited; - - // digest the forward event - mTimelineLiveEventHandler.handleLiveEvent(event, !isLimited && !mIsGlobalInitialSync, !mIsGlobalInitialSync && !isRoomInitialSync); - } catch (Exception e) { - Log.e(LOG_TAG, "timeline event failed " + e.getMessage(), e); - } - } - } - } - - private void handleLiveTimeline(@NonNull final MXDataHandler dataHandler, - @NonNull final IMXStore store, - @NonNull final String roomId, - @NonNull final String myUserId, - @Nullable final RoomSummary currentSummary) { - final RoomState state = mTimelineStateHolder.getState(); - // check if the summary is defined - // after a sync, the room summary might not be defined because the latest message did not generate a room summary/ - if (null != store.getRoom(roomId)) { - RoomSummary summary = store.getSummary(roomId); - // if there is no defined summary - // we have to create a new one - if (summary == null) { - // define a summary if some messages are left - // the unsent messages are often displayed messages. - final Event oldestEvent = store.getOldestEvent(roomId); - - // if there is an oldest event, use it to set a summary - if (oldestEvent != null) { - // always defined a room summary else the room won't be displayed in the recents - store.storeSummary(new RoomSummary(null, oldestEvent, state, myUserId)); - store.commit(); - - // if the event is not displayable - // back paginate until to find a valid one - if (!RoomSummary.isSupportedEvent(oldestEvent)) { - Log.e(LOG_TAG, "the room " + roomId + " has no valid summary, back paginate once to find a valid one"); - } - } - // use the latest known event - else if (currentSummary != null) { - currentSummary.setLatestReceivedEvent(currentSummary.getLatestReceivedEvent(), state); - store.storeSummary(currentSummary); - store.commit(); - } - // try to build a summary from the state events - else if (mRoomSync.state != null && mRoomSync.state.events != null && mRoomSync.state.events.size() > 0) { - final List events = new ArrayList<>(mRoomSync.state.events); - Collections.reverse(events); - - for (Event event : events) { - event.roomId = roomId; - if (RoomSummary.isSupportedEvent(event)) { - summary = new RoomSummary(store.getSummary(roomId), event, state, myUserId); - store.storeSummary(summary); - store.commit(); - break; - } - } - } - } - } - - if (null != mRoomSync.unreadNotifications) { - int notifCount = 0; - int highlightCount = 0; - - if (null != mRoomSync.unreadNotifications.highlightCount) { - highlightCount = mRoomSync.unreadNotifications.highlightCount; - } - - if (null != mRoomSync.unreadNotifications.notificationCount) { - notifCount = mRoomSync.unreadNotifications.notificationCount; - } - - if (notifCount != state.getNotificationCount() || state.getHighlightCount() != highlightCount) { - Log.d(LOG_TAG, "## handleJoinedRoomSync() : update room state notifs count for room id " + roomId - + ": highlightCount " + highlightCount + " - notifCount " + notifCount); - - state.setNotificationCount(notifCount); - state.setHighlightCount(highlightCount); - store.storeLiveStateForRoom(roomId); - dataHandler.onNotificationCountUpdate(roomId); - } - - // some users reported that the summary notification counts were sometimes invalid - // so check roomstates and summaries separately - final RoomSummary summary = store.getSummary(roomId); - if (summary != null && (notifCount != summary.getNotificationCount() || summary.getHighlightCount() != highlightCount)) { - Log.d(LOG_TAG, "## handleJoinedRoomSync() : update room summary notifs count for room id " + roomId - + ": highlightCount " + highlightCount + " - notifCount " + notifCount); - - summary.setNotificationCount(notifCount); - summary.setHighlightCount(highlightCount); - store.flushSummary(summary); - dataHandler.onNotificationCountUpdate(roomId); - } - } - - // TODO LazyLoading, maybe this should be done earlier, because nb of members can be usefull in the instruction above. - if (mRoomSync.roomSyncSummary != null) { - RoomSummary summary = store.getSummary(roomId); - - if (summary == null) { - // Should never happen here - Log.e(LOG_TAG, "!!!!!!!!!!!!!!!!!!!!! RoomSummary is null !!!!!!!!!!!!!!!!!!!!!"); - } else { - summary.setRoomSyncSummary(mRoomSync.roomSyncSummary); - - store.flushSummary(summary); - } - } - } - -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/TimelineLiveEventHandler.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/TimelineLiveEventHandler.java deleted file mode 100644 index 0b81de42..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/TimelineLiveEventHandler.java +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.data.timeline; - -import android.support.annotation.NonNull; -import android.text.TextUtils; - -import java.util.ArrayList; -import java.util.List; - -import javax.annotation.Nonnull; - -import im.vector.matrix.android.internal.legacy.MXDataHandler; -import im.vector.matrix.android.internal.legacy.data.MyUser; -import im.vector.matrix.android.internal.legacy.data.Room; -import im.vector.matrix.android.internal.legacy.data.RoomState; -import im.vector.matrix.android.internal.legacy.data.RoomSummary; -import im.vector.matrix.android.internal.legacy.data.store.IMXStore; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.EventContent; -import im.vector.matrix.android.internal.legacy.rest.model.RoomMember; -import im.vector.matrix.android.internal.legacy.util.EventDisplay; -import im.vector.matrix.android.internal.legacy.util.JsonUtils; -import im.vector.matrix.android.internal.legacy.util.Log; - -/** - * This class is responsible for handling live event - */ -class TimelineLiveEventHandler { - - private static final String LOG_TAG = TimelineLiveEventHandler.class.getSimpleName(); - - private final MXEventTimeline mEventTimeline; - private final TimelineEventSaver mTimelineEventSaver; - private final StateEventRedactionChecker mStateEventRedactionChecker; - private final TimelinePushWorker mTimelinePushWorker; - private final TimelineStateHolder mTimelineStateHolder; - private final TimelineEventListeners mEventListeners; - - TimelineLiveEventHandler(@Nonnull final MXEventTimeline eventTimeline, - @Nonnull final TimelineEventSaver timelineEventSaver, - @Nonnull final StateEventRedactionChecker stateEventRedactionChecker, - @Nonnull final TimelinePushWorker timelinePushWorker, - @NonNull final TimelineStateHolder timelineStateHolder, - @NonNull final TimelineEventListeners eventListeners) { - mEventTimeline = eventTimeline; - mTimelineEventSaver = timelineEventSaver; - mStateEventRedactionChecker = stateEventRedactionChecker; - mTimelinePushWorker = timelinePushWorker; - mTimelineStateHolder = timelineStateHolder; - mEventListeners = eventListeners; - } - - /** - * Handle events coming down from the event stream. - * - * @param event the live event - * @param checkRedactedStateEvent set to true to check if it triggers a state event redaction - * @param withPush set to true to trigger pushes when it is required - */ - public void handleLiveEvent(@NonNull final Event event, - final boolean checkRedactedStateEvent, - final boolean withPush) { - final IMXStore store = mEventTimeline.getStore(); - final Room room = mEventTimeline.getRoom(); - final MXDataHandler dataHandler = room.getDataHandler(); - final String timelineId = mEventTimeline.getTimelineId(); - final MyUser myUser = dataHandler.getMyUser(); - - // Decrypt event if necessary - dataHandler.decryptEvent(event, timelineId); - - // dispatch the call events to the calls manager - if (event.isCallEvent()) { - final RoomState roomState = mTimelineStateHolder.getState(); - dataHandler.getCallsManager().handleCallEvent(store, event); - storeLiveRoomEvent(dataHandler, store, event, false); - // the candidates events are not tracked - // because the users don't need to see the peer exchanges. - if (!TextUtils.equals(event.getType(), Event.EVENT_TYPE_CALL_CANDIDATES)) { - // warn the listeners - // general listeners - dataHandler.onLiveEvent(event, roomState); - // timeline listeners - mEventListeners.onEvent(event, EventTimeline.Direction.FORWARDS, roomState); - } - - // trigger pushes when it is required - if (withPush) { - mTimelinePushWorker.triggerPush(roomState, event); - } - - } else { - final Event storedEvent = store.getEvent(event.eventId, event.roomId); - - // avoid processing event twice - if (storedEvent != null) { - // an event has been echoed - if (storedEvent.getAge() == Event.DUMMY_EVENT_AGE) { - store.deleteEvent(storedEvent); - store.storeLiveRoomEvent(event); - store.commit(); - Log.d(LOG_TAG, "handleLiveEvent : the event " + event.eventId + " in " + event.roomId + " has been echoed"); - } else { - Log.d(LOG_TAG, "handleLiveEvent : the event " + event.eventId + " in " + event.roomId + " already exist."); - return; - } - } - - // Room event - if (event.roomId != null) { - // check if the room has been joined - // the initial sync + the first requestHistory call is done here - // instead of being done in the application - if (Event.EVENT_TYPE_STATE_ROOM_MEMBER.equals(event.getType()) && TextUtils.equals(event.getSender(), dataHandler.getUserId())) { - EventContent eventContent = JsonUtils.toEventContent(event.getContentAsJsonObject()); - EventContent prevEventContent = event.getPrevContent(); - - String prevMembership = null; - - if (prevEventContent != null) { - prevMembership = prevEventContent.membership; - } - - // if the membership keeps the same value "join". - // it should mean that the user profile has been updated. - if (!event.isRedacted() && TextUtils.equals(prevMembership, eventContent.membership) - && TextUtils.equals(RoomMember.MEMBERSHIP_JOIN, eventContent.membership)) { - // check if the user updates his profile from another device. - - boolean hasAccountInfoUpdated = false; - - if (!TextUtils.equals(eventContent.displayname, myUser.displayname)) { - hasAccountInfoUpdated = true; - myUser.displayname = eventContent.displayname; - store.setDisplayName(myUser.displayname, event.getOriginServerTs()); - } - - if (!TextUtils.equals(eventContent.avatar_url, myUser.getAvatarUrl())) { - hasAccountInfoUpdated = true; - myUser.setAvatarUrl(eventContent.avatar_url); - store.setAvatarURL(myUser.avatar_url, event.getOriginServerTs()); - } - - if (hasAccountInfoUpdated) { - dataHandler.onAccountInfoUpdate(myUser); - } - } - } - - final RoomState previousState = mTimelineStateHolder.getState(); - if (event.stateKey != null) { - // copy the live state before applying any update - mTimelineStateHolder.deepCopyState(EventTimeline.Direction.FORWARDS); - // check if the event has been processed - if (!mTimelineStateHolder.processStateEvent(event, EventTimeline.Direction.FORWARDS)) { - // not processed -> do not warn the application - // assume that the event is a duplicated one. - return; - } - } - storeLiveRoomEvent(dataHandler, store, event, checkRedactedStateEvent); - - // warn the listeners - // general listeners - dataHandler.onLiveEvent(event, previousState); - - // timeline listeners - mEventListeners.onEvent(event, EventTimeline.Direction.FORWARDS, previousState); - - // trigger pushes when it is required - if (withPush) { - mTimelinePushWorker.triggerPush(mTimelineStateHolder.getState(), event); - } - } else { - Log.e(LOG_TAG, "Unknown live event type: " + event.getType()); - } - } - } - - /** - * Store a live room event. - * - * @param event The event to be stored. - * @param checkRedactedStateEvent true to check if this event redacts a state event - */ - private void storeLiveRoomEvent(@NonNull final MXDataHandler dataHandler, - @NonNull final IMXStore store, - @NonNull Event event, - final boolean checkRedactedStateEvent) { - boolean shouldBeSaved = false; - String myUserId = dataHandler.getCredentials().getUserId(); - - if (Event.EVENT_TYPE_REDACTION.equals(event.getType())) { - if (event.getRedactedEventId() != null) { - Event eventToPrune = store.getEvent(event.getRedactedEventId(), event.roomId); - - // when an event is redacted, some fields must be kept. - if (eventToPrune != null) { - shouldBeSaved = true; - // remove expected keys - eventToPrune.prune(event); - // store the prune event - mTimelineEventSaver.storeEvent(eventToPrune); - // store the redaction event too (for the read markers management) - mTimelineEventSaver.storeEvent(event); - // the redaction check must not be done during an initial sync - // or the redacted event is received with roomSync.timeline.limited - if (checkRedactedStateEvent && eventToPrune.stateKey != null) { - mStateEventRedactionChecker.checkStateEventRedaction(event); - } - // search the latest displayable event - // to replace the summary text - final List events = new ArrayList<>(store.getRoomMessages(event.roomId)); - for (int index = events.size() - 1; index >= 0; index--) { - final Event indexedEvent = events.get(index); - if (RoomSummary.isSupportedEvent(indexedEvent)) { - // Decrypt event if necessary - if (TextUtils.equals(indexedEvent.getType(), Event.EVENT_TYPE_MESSAGE_ENCRYPTED)) { - if (null != dataHandler.getCrypto()) { - dataHandler.decryptEvent(indexedEvent, mEventTimeline.getTimelineId()); - } - } - final RoomState state = mTimelineStateHolder.getState(); - final EventDisplay eventDisplay = new EventDisplay(store.getContext(), indexedEvent, state); - // ensure that message can be displayed - if (!TextUtils.isEmpty(eventDisplay.getTextualDisplay())) { - event = indexedEvent; - break; - } - } - - } - } else if (checkRedactedStateEvent) { - // the redaction check must not be done during an initial sync - // or the redacted event is received with roomSync.timeline.limited - mStateEventRedactionChecker.checkStateEventRedaction(event); - } - } - } else { - // the candidate events are not stored. - shouldBeSaved = !event.isCallEvent() || !Event.EVENT_TYPE_CALL_CANDIDATES.equals(event.getType()); - // thread issue - // if the user leaves a room, - if (Event.EVENT_TYPE_STATE_ROOM_MEMBER.equals(event.getType()) && myUserId.equals(event.stateKey)) { - final String membership = event.getContentAsJsonObject().getAsJsonPrimitive("membership").getAsString(); - if (RoomMember.MEMBERSHIP_LEAVE.equals(membership) || RoomMember.MEMBERSHIP_BAN.equals(membership)) { - shouldBeSaved = mEventTimeline.isHistorical(); - // delete the room and warn the listener of the leave event only at the end of the events chunk processing - } - } - } - if (shouldBeSaved) { - mTimelineEventSaver.storeEvent(event); - } - // warn the listener that a new room has been created - if (Event.EVENT_TYPE_STATE_ROOM_CREATE.equals(event.getType())) { - dataHandler.onNewRoom(event.roomId); - } - // warn the listeners that a room has been joined - if (Event.EVENT_TYPE_STATE_ROOM_MEMBER.equals(event.getType()) && myUserId.equals(event.stateKey)) { - final String membership = event.getContentAsJsonObject().getAsJsonPrimitive("membership").getAsString(); - if (RoomMember.MEMBERSHIP_JOIN.equals(membership)) { - dataHandler.onJoinRoom(event.roomId); - } else if (RoomMember.MEMBERSHIP_INVITE.equals(membership)) { - dataHandler.onNewRoom(event.roomId); - } - } - } - -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/TimelinePushWorker.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/TimelinePushWorker.java deleted file mode 100644 index c97fe034..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/TimelinePushWorker.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.data.timeline; - -import android.support.annotation.NonNull; - -import com.google.gson.JsonObject; - -import im.vector.matrix.android.internal.legacy.MXDataHandler; -import im.vector.matrix.android.internal.legacy.call.MXCall; -import im.vector.matrix.android.internal.legacy.data.RoomState; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.BingRule; -import im.vector.matrix.android.internal.legacy.util.BingRulesManager; -import im.vector.matrix.android.internal.legacy.util.Log; - -/** - * This class is responsible for handling push rules for an event - */ -class TimelinePushWorker { - - private static final String LOG_TAG = TimelinePushWorker.class.getSimpleName(); - - private final MXDataHandler mDataHandler; - - TimelinePushWorker(@NonNull final MXDataHandler dataHandler) { - mDataHandler = dataHandler; - } - - /** - * Trigger a push if there is a dedicated push rules which implies it. - * - * @param event the event - */ - public void triggerPush(@NonNull final RoomState state, - @NonNull final Event event) { - BingRule bingRule; - boolean outOfTimeEvent = false; - long maxLifetime = 0; - long eventLifetime = 0; - final JsonObject eventContent = event.getContentAsJsonObject(); - if (eventContent != null && eventContent.has("lifetime")) { - maxLifetime = eventContent.get("lifetime").getAsLong(); - eventLifetime = System.currentTimeMillis() - event.getOriginServerTs(); - outOfTimeEvent = eventLifetime > maxLifetime; - } - final BingRulesManager bingRulesManager = mDataHandler.getBingRulesManager(); - // If the bing rules apply, bing - if (!outOfTimeEvent - && bingRulesManager != null - && (bingRule = bingRulesManager.fulfilledBingRule(event)) != null) { - - if (bingRule.shouldNotify()) { - // bing the call events only if they make sense - if (Event.EVENT_TYPE_CALL_INVITE.equals(event.getType())) { - long lifeTime = event.getAge(); - if (Long.MAX_VALUE == lifeTime) { - lifeTime = System.currentTimeMillis() - event.getOriginServerTs(); - } - if (lifeTime > MXCall.CALL_TIMEOUT_MS) { - Log.d(LOG_TAG, "IGNORED onBingEvent rule id " + bingRule.ruleId + " event id " + event.eventId - + " in " + event.roomId); - return; - } - } - Log.d(LOG_TAG, "onBingEvent rule id " + bingRule.ruleId + " event id " + event.eventId + " in " + event.roomId); - mDataHandler.onBingEvent(event, state, bingRule); - } else { - Log.d(LOG_TAG, "rule id " + bingRule.ruleId + " event id " + event.eventId - + " in " + event.roomId + " has a mute notify rule"); - } - } else if (outOfTimeEvent) { - Log.e(LOG_TAG, "outOfTimeEvent for " + event.eventId + " in " + event.roomId); - Log.e(LOG_TAG, "outOfTimeEvent maxlifetime " + maxLifetime + " eventLifeTime " + eventLifetime); - } - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/TimelineStateHolder.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/TimelineStateHolder.java deleted file mode 100644 index 1e40769f..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/data/timeline/TimelineStateHolder.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.data.timeline; - -import android.support.annotation.NonNull; - -import im.vector.matrix.android.internal.legacy.MXDataHandler; -import im.vector.matrix.android.internal.legacy.data.RoomState; -import im.vector.matrix.android.internal.legacy.data.store.IMXStore; -import im.vector.matrix.android.internal.legacy.rest.model.Event; - -/** - * This class is responsible for holding the state and backState of a room timeline - */ -class TimelineStateHolder { - - private final MXDataHandler mDataHandler; - private final IMXStore mStore; - private String mRoomId; - - /** - * The state of the room at the top most recent event of the timeline. - */ - private RoomState mState; - - /** - * The historical state of the room when paginating back. - */ - private RoomState mBackState; - - TimelineStateHolder(@NonNull final MXDataHandler dataHandler, - @NonNull final IMXStore store, - @NonNull final String roomId) { - mDataHandler = dataHandler; - mStore = store; - mRoomId = roomId; - initStates(); - } - - /** - * Clear the states - */ - public void clear() { - initStates(); - } - - /** - * @return The state of the room at the top most recent event of the timeline. - */ - @NonNull - public RoomState getState() { - return mState; - } - - /** - * Update the state. - * - * @param state the new state. - */ - public void setState(@NonNull final RoomState state) { - mState = state; - } - - /** - * @return the backState. - */ - @NonNull - public RoomState getBackState() { - return mBackState; - } - - /** - * Update the backState. - * - * @param state the new backState. - */ - public void setBackState(@NonNull final RoomState state) { - mBackState = state; - } - - /** - * Make a deep copy or the dedicated state. - * - * @param direction the room state direction to deep copy. - */ - public void deepCopyState(final EventTimeline.Direction direction) { - if (direction == EventTimeline.Direction.FORWARDS) { - mState = mState.deepCopy(); - } else { - mBackState = mBackState.deepCopy(); - } - } - - /** - * Process a state event to keep the internal live and back states up to date. - * - * @param event the state event - * @param direction the direction; ie. forwards for live state, backwards for back state - * @return true if the event has been processed. - */ - public boolean processStateEvent(@NonNull final Event event, - @NonNull final EventTimeline.Direction direction) { - final RoomState affectedState = direction == EventTimeline.Direction.FORWARDS ? mState : mBackState; - final boolean isProcessed = affectedState.applyState(mStore, event, direction); - if (isProcessed && direction == EventTimeline.Direction.FORWARDS) { - mStore.storeLiveStateForRoom(mRoomId); - } - return isProcessed; - } - - /** - * Set the room Id - * - * @param roomId the new room id. - */ - public void setRoomId(@NonNull final String roomId) { - mRoomId = roomId; - mState.roomId = roomId; - mBackState.roomId = roomId; - } - - /** - * Initialize the state and backState to default, with roomId and dataHandler - */ - private void initStates() { - mBackState = new RoomState(); - mBackState.setDataHandler(mDataHandler); - mBackState.roomId = mRoomId; - mState = new RoomState(); - mState.setDataHandler(mDataHandler); - mState.roomId = mRoomId; - } - - -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/db/MXLatestChatMessageCache.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/db/MXLatestChatMessageCache.java deleted file mode 100644 index c1e16412..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/db/MXLatestChatMessageCache.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright 2015 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.db; - -import android.content.Context; -import android.text.TextUtils; - -import im.vector.matrix.android.internal.legacy.util.ContentUtils; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.util.HashMap; -import java.util.Map; - -public class MXLatestChatMessageCache { - private static final String LOG_TAG = MXLatestChatMessageCache.class.getSimpleName(); - private static final String FILENAME = "ConsoleLatestChatMessageCache"; - - final String MXLATESTMESSAGES_STORE_FOLDER = "MXLatestMessagesStore"; - - private Map mLatestMesssageByRoomId = null; - private String mUserId = null; - private File mLatestMessagesDirectory = null; - private File mLatestMessagesFile = null; - - /** - * Constructor - * - * @param userId the user id - */ - public MXLatestChatMessageCache(String userId) { - mUserId = userId; - } - - /** - * Clear the text caches. - * - * @param context The application context to use. - */ - public void clearCache(Context context) { - ContentUtils.deleteDirectory(mLatestMessagesDirectory); - mLatestMesssageByRoomId = null; - } - - /** - * Open the texts cache file. - * - * @param context the context. - */ - private void openLatestMessagesDict(Context context) { - - // already checked - if (null != mLatestMesssageByRoomId) { - return; - } - - mLatestMesssageByRoomId = new HashMap<>(); - - try { - mLatestMessagesDirectory = new File(context.getApplicationContext().getFilesDir(), MXLATESTMESSAGES_STORE_FOLDER); - mLatestMessagesDirectory = new File(mLatestMessagesDirectory, mUserId); - - mLatestMessagesFile = new File(mLatestMessagesDirectory, FILENAME.hashCode() + ""); - - if (!mLatestMessagesDirectory.exists()) { - - // create dir tree - mLatestMessagesDirectory.mkdirs(); - - File oldFile = new File(context.getApplicationContext().getFilesDir(), FILENAME.hashCode() + ""); - - // backward compatibility - if (oldFile.exists()) { - oldFile.renameTo(mLatestMessagesFile); - } - } - - if (mLatestMessagesFile.exists()) { - FileInputStream fis = new FileInputStream(mLatestMessagesFile); - ObjectInputStream ois = new ObjectInputStream(fis); - mLatestMesssageByRoomId = (Map) ois.readObject(); - ois.close(); - fis.close(); - } - } catch (Exception e) { - Log.e(LOG_TAG, "## openLatestMessagesDict failed " + e.getMessage(), e); - } - } - - /** - * Get the latest written text for a dedicated room. - * - * @param context the context. - * @param roomId the roomId - * @return the latest message - */ - public String getLatestText(Context context, String roomId) { - if (null == mLatestMesssageByRoomId) { - openLatestMessagesDict(context); - } - - if (TextUtils.isEmpty(roomId)) { - return ""; - } - - if (mLatestMesssageByRoomId.containsKey(roomId)) { - return mLatestMesssageByRoomId.get(roomId); - } - - return ""; - } - - /** - * Update the latest message dictionnary. - * - * @param context the context. - */ - private void saveLatestMessagesDict(Context context) { - try { - FileOutputStream fos = new FileOutputStream(mLatestMessagesFile); - ObjectOutputStream oos = new ObjectOutputStream(fos); - oos.writeObject(mLatestMesssageByRoomId); - oos.close(); - fos.close(); - } catch (Exception e) { - Log.e(LOG_TAG, "## saveLatestMessagesDict() failed " + e.getMessage(), e); - } - } - - /** - * Update the latest message for a dedicated roomId. - * - * @param context the context. - * @param roomId the roomId. - * @param message the message. - */ - public void updateLatestMessage(Context context, String roomId, String message) { - if (null == mLatestMesssageByRoomId) { - openLatestMessagesDict(context); - } - - if (TextUtils.isEmpty(message)) { - mLatestMesssageByRoomId.remove(roomId); - } - - mLatestMesssageByRoomId.put(roomId, message); - saveLatestMessagesDict(context); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/db/MXMediaDownloadWorkerTask.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/db/MXMediaDownloadWorkerTask.java deleted file mode 100644 index 27ef7230..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/db/MXMediaDownloadWorkerTask.java +++ /dev/null @@ -1,1158 +0,0 @@ -/* - * Copyright 2015 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.db; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.net.Uri; -import android.os.AsyncTask; -import android.support.annotation.Nullable; -import android.support.v4.util.LruCache; -import android.text.TextUtils; -import android.util.Pair; -import android.webkit.MimeTypeMap; -import android.widget.ImageView; - -import com.google.gson.JsonElement; -import com.google.gson.JsonParser; - -import org.matrix.olm.OlmPkEncryption; -import org.matrix.olm.OlmPkMessage; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.lang.ref.WeakReference; -import java.net.HttpURLConnection; -import java.net.URL; -import java.security.MessageDigest; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.X509TrustManager; - -import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig; -import im.vector.matrix.android.internal.legacy.RestClient; -import im.vector.matrix.android.internal.legacy.crypto.MXEncryptedAttachments; -import im.vector.matrix.android.internal.legacy.listeners.IMXMediaDownloadListener; -import im.vector.matrix.android.internal.legacy.network.NetworkConnectivityReceiver; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.SimpleApiCallback; -import im.vector.matrix.android.internal.legacy.rest.client.MediaScanRestClient; -import im.vector.matrix.android.internal.legacy.rest.model.EncryptedMediaScanBody; -import im.vector.matrix.android.internal.legacy.rest.model.EncryptedMediaScanEncryptedBody; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.EncryptedBodyFileInfo; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.EncryptedFileInfo; -import im.vector.matrix.android.internal.legacy.util.ImageUtils; -import im.vector.matrix.android.internal.legacy.util.JsonUtils; -import im.vector.matrix.android.internal.legacy.util.Log; -import im.vector.matrix.android.internal.network.ssl.CertUtil; - -/** - * This class manages the media downloading in background. - *

- * JsonElement: Error message if not null. - */ -class MXMediaDownloadWorkerTask extends AsyncTask { - - private static final String LOG_TAG = MXMediaDownloadWorkerTask.class.getSimpleName(); - - /** - * Pending media URLs - */ - private static final Map sPendingDownloadById = new HashMap<>(); - - /** - * List of unreachable media urls. - */ - private static final List sUnreachableUrls = new ArrayList<>(); - - // avoid sync on "this" because it might differ if there is a timer. - private static final Object sSyncObject = new Object(); - - /** - * The medias cache - */ - private static LruCache sBitmapByDownloadIdCache = null; - - /** - * The downloaded media callbacks. - */ - private final List mDownloadListeners = new ArrayList<>(); - - /** - * The ImageView list to refresh when the media is downloaded. - */ - private final List> mImageViewReferences; - - /** - * The media URL. - */ - private String mUrl; - - /** - * The download identifier based on the original matrix content url for this media. - */ - private String mDownloadId; - - /** - * Tells if the anti-virus scanner is enabled. - */ - private boolean mIsAvScannerEnabled; - - /** - * The media mime type - */ - private String mMimeType; - - /** - * The application context - */ - private Context mApplicationContext; - - /** - * The directory in which the media must be stored. - */ - private File mDirectoryFile; - - /** - * The rotation to apply. - */ - private int mRotation; - - /** - * The download stats. - */ - private IMXMediaDownloadListener.DownloadStats mDownloadStats; - - /** - * Tells the download has been cancelled. - */ - private boolean mIsDownloadCancelled; - - /** - * Tells if the download has been completed - */ - private boolean mIsDone; - - /** - * The home server config. - */ - private final HomeServerConnectionConfig mHsConfig; - - /** - * The bitmap to use when the URL is unreachable. - */ - private Bitmap mDefaultBitmap; - - /** - * the encrypted file information - */ - private final EncryptedFileInfo mEncryptedFileInfo; - - /** - * Network updates tracker - */ - private final NetworkConnectivityReceiver mNetworkConnectivityReceiver; - - /** - * Rest client to retrieve public antivirus server key - */ - @Nullable - private MediaScanRestClient mMediaScanRestClient; - - /** - * Download constants - */ - private static final int DOWNLOAD_TIME_OUT = 10 * 1000; - private static final int DOWNLOAD_BUFFER_READ_SIZE = 1024 * 32; - - //============================================================================================================== - // static methods - //============================================================================================================== - - /** - * Clear the internal cache. - */ - public static void clearBitmapsCache() { - if (null != sBitmapByDownloadIdCache) { - sBitmapByDownloadIdCache.evictAll(); - } - - // Clear the list of unreachable Urls, to retry to download it on next access - synchronized (sUnreachableUrls) { - sUnreachableUrls.clear(); - } - } - - /** - * Check if there is a pending download with the provided id. - * - * @param downloadId The identifier to check - * @return the dedicated MXMediaDownloadWorkerTask if it exists. - */ - public static MXMediaDownloadWorkerTask getMediaDownloadWorkerTask(String downloadId) { - if (sPendingDownloadById.containsKey(downloadId)) { - MXMediaDownloadWorkerTask task; - synchronized (sPendingDownloadById) { - task = sPendingDownloadById.get(downloadId); - } - return task; - } else { - return null; - } - } - - /** - * Generate an unique ID for a string - * - * @param input the string - * @return the unique ID - */ - private static String uniqueId(String input) { - String uniqueId = null; - - try { - MessageDigest mDigest = MessageDigest.getInstance("SHA1"); - byte[] result = mDigest.digest(input.getBytes()); - StringBuffer sb = new StringBuffer(); - - for (int i = 0; i < result.length; i++) { - sb.append(Integer.toString((result[i] & 0xff) + 0x100, 16).substring(1)); - } - - uniqueId = sb.toString(); - } catch (Exception e) { - Log.e(LOG_TAG, "uniqueId failed " + e.getMessage(), e); - } - - if (null == uniqueId) { - uniqueId = "" + Math.abs(input.hashCode() + (System.currentTimeMillis() + "").hashCode()); - } - - return uniqueId; - } - - /** - * Build a filename from a download Id - * - * @param downloadId the media url - * @param mimeType the mime type; - * @return the cache filename - */ - static String buildFileName(String downloadId, String mimeType) { - String name = "file_" + uniqueId(downloadId); - - if (!TextUtils.isEmpty(mimeType)) { - String fileExtension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType); - - // some devices don't support .jpeg files - if ("jpeg".equals(fileExtension)) { - fileExtension = "jpg"; - } - - if (null != fileExtension) { - name += "." + fileExtension; - } - } - - return name; - } - - /** - * Tell if the media is cached with the provided cache identifier - * - * @param mediaCacheId - * @return true if a media is cached with this identifier - */ - public static boolean isMediaCached(String mediaCacheId) { - boolean res = false; - - if ((null != sBitmapByDownloadIdCache)) { - synchronized (sSyncObject) { - res = (null != sBitmapByDownloadIdCache.get(mediaCacheId)); - } - } - - return res; - } - - /** - * Tells if the media URL is unreachable. - * - * @param url the url to test. - * @return true if the media URL is unreachable. - */ - public static boolean isMediaUrlUnreachable(String url) { - boolean res = true; - - if (!TextUtils.isEmpty(url)) { - synchronized (sUnreachableUrls) { - res = sUnreachableUrls.contains(url); - } - } - - return res; - } - - /** - * Search a cached bitmap from an url. - * rotationAngle is set to Integer.MAX_VALUE when undefined : the EXIF metadata must be checked. - * - * @param baseFile the base file - * @param url the actual media url - * @param downloadId the predefined id of the download task for this content - * @param aRotation the bitmap rotation - * @param mimeType the mime type - * @param encryptionInfo the encryption information - * @return true if the bitmap is cached - */ - static boolean bitmapForURL(final Context context, - final File baseFile, - final String url, - final String downloadId, - final int aRotation, - final String mimeType, - final EncryptedFileInfo encryptionInfo, - final ApiCallback callback) { - if (TextUtils.isEmpty(url)) { - Log.d(LOG_TAG, "bitmapForURL : null url"); - return false; - } - - if (null == sBitmapByDownloadIdCache) { - int lruSize = Math.min(20 * 1024 * 1024, (int) Runtime.getRuntime().maxMemory() / 8); - - Log.d(LOG_TAG, "bitmapForURL lruSize : " + lruSize); - - sBitmapByDownloadIdCache = new LruCache(lruSize) { - @Override - protected int sizeOf(String key, Bitmap bitmap) { - return bitmap.getRowBytes() * bitmap.getHeight(); // size in bytes - } - }; - } - - // the image is downloading in background - if (null != getMediaDownloadWorkerTask(downloadId)) { - return false; - } - - // the url is invalid - if (isMediaUrlUnreachable(url)) { - return false; - } - - final Bitmap cachedBitmap; - - synchronized (sSyncObject) { - cachedBitmap = sBitmapByDownloadIdCache.get(downloadId); - } - - if (null != cachedBitmap) { - MXMediasCache.mUIHandler.post(new Runnable() { - @Override - public void run() { - callback.onSuccess(cachedBitmap); - } - }); - return true; - } - - // invalid basefile - if (null == baseFile) { - return false; - } - - // check if the image has not been saved in file system - String filename = null; - - // the url is a file one - if (url.startsWith("file:")) { - // try to parse it - try { - Uri uri = Uri.parse(url); - filename = uri.getPath(); - } catch (Exception e) { - Log.e(LOG_TAG, "bitmapForURL #1 : " + e.getMessage(), e); - } - - // cannot extract the filename -> sorry - if (null == filename) { - return false; - } - } - - // not a valid file name - if (null == filename) { - filename = buildFileName(downloadId, mimeType); - } - - final String fFilename = filename; - final File file = filename.startsWith(File.separator) ? new File(filename) : new File(baseFile, filename); - - if (!file.exists()) { - return false; - } - - MXMediasCache.mDecryptingHandler.post(new Runnable() { - @Override - public void run() { - Bitmap bitmap = null; - int rotation = aRotation; - - try { - - InputStream fis = new FileInputStream(file); - - if (null != encryptionInfo) { - InputStream decryptedIs = MXEncryptedAttachments.decryptAttachment(fis, encryptionInfo); - fis.close(); - fis = decryptedIs; - } - - // read the metadata - if (Integer.MAX_VALUE == rotation) { - rotation = ImageUtils.getRotationAngleForBitmap(context, Uri.fromFile(file)); - } - - if (null != fis) { - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inPreferredConfig = Bitmap.Config.ARGB_8888; - - try { - bitmap = BitmapFactory.decodeStream(fis, null, options); - } catch (OutOfMemoryError error) { - System.gc(); - Log.e(LOG_TAG, "bitmapForURL() : Out of memory 1 " + error, error); - } - - // try again - if (null == bitmap) { - try { - bitmap = BitmapFactory.decodeStream(fis, null, options); - } catch (OutOfMemoryError error) { - Log.e(LOG_TAG, "bitmapForURL() Out of memory 2 " + error, error); - } - } - - if (null != bitmap) { - synchronized (sSyncObject) { - if (0 != rotation) { - try { - android.graphics.Matrix bitmapMatrix = new android.graphics.Matrix(); - bitmapMatrix.postRotate(rotation); - - Bitmap transformedBitmap = Bitmap.createBitmap(bitmap, - 0, 0, bitmap.getWidth(), bitmap.getHeight(), bitmapMatrix, false); - - // Bitmap.createBitmap() can return the same bitmap, so do not recycle it if it is the case - if (transformedBitmap != bitmap) { - bitmap.recycle(); - } - - bitmap = transformedBitmap; - } catch (OutOfMemoryError ex) { - Log.e(LOG_TAG, "bitmapForURL rotation error : " + ex.getMessage(), ex); - } - } - - // cache only small images - // caching large images does not make sense - // it would replace small ones. - // let assume that the application must be faster when showing the chat history. - if ((bitmap.getWidth() < 1000) && (bitmap.getHeight() < 1000)) { - sBitmapByDownloadIdCache.put(downloadId, bitmap); - } - } - } - - fis.close(); - } - - } catch (FileNotFoundException e) { - Log.d(LOG_TAG, "bitmapForURL() : " + fFilename + " does not exist"); - } catch (Exception e) { - Log.e(LOG_TAG, "bitmapForURL() " + e, e); - - } - - final Bitmap fBitmap = bitmap; - MXMediasCache.mUIHandler.post(new Runnable() { - @Override - public void run() { - callback.onSuccess(fBitmap); - } - }); - } - }); - - return true; - } - - //============================================================================================================== - // class methods - //============================================================================================================== - - /** - * MXMediaDownloadWorkerTask creator - * - * @param appContext the context - * @param hsConfig the home server config - * @param networkConnectivityReceiver the network connectivity receiver - * @param directoryFile the directory in which the media must be stored - * @param url the media url - * @param downloadId the predefined id of the download task for this content - * @param rotation the rotation angle (degrees), use 0 by default - * @param mimeType the mime type. - * @param encryptedFileInfo the encryption information - * @param mediaScanRestClient the media scan rest client - * @param isAvScannerEnabled tell whether an anti-virus scanner is enabled - */ - public MXMediaDownloadWorkerTask(Context appContext, - HomeServerConnectionConfig hsConfig, - NetworkConnectivityReceiver networkConnectivityReceiver, - File directoryFile, - String url, - String downloadId, - int rotation, - String mimeType, - EncryptedFileInfo encryptedFileInfo, - @Nullable MediaScanRestClient mediaScanRestClient, - boolean isAvScannerEnabled) { - mApplicationContext = appContext; - mHsConfig = hsConfig; - mNetworkConnectivityReceiver = networkConnectivityReceiver; - mDirectoryFile = directoryFile; - mUrl = url; - mDownloadId = downloadId; - mRotation = rotation; - mMimeType = mimeType; - mEncryptedFileInfo = encryptedFileInfo; - mMediaScanRestClient = mediaScanRestClient; - mIsAvScannerEnabled = isAvScannerEnabled; - - mImageViewReferences = new ArrayList<>(); - - synchronized (sPendingDownloadById) { - sPendingDownloadById.put(downloadId, this); - } - } - - /** - * MXMediaDownloadWorkerTask creator - * - * @param task another bitmap task - */ - public MXMediaDownloadWorkerTask(MXMediaDownloadWorkerTask task) { - mApplicationContext = task.mApplicationContext; - mHsConfig = task.mHsConfig; - mNetworkConnectivityReceiver = task.mNetworkConnectivityReceiver; - mDirectoryFile = task.mDirectoryFile; - mUrl = task.mUrl; - mDownloadId = task.mDownloadId; - mRotation = task.mRotation; - mMimeType = task.mMimeType; - mEncryptedFileInfo = task.mEncryptedFileInfo; - mIsAvScannerEnabled = task.mIsAvScannerEnabled; - mMediaScanRestClient = task.mMediaScanRestClient; - - mImageViewReferences = task.mImageViewReferences; - - synchronized (sPendingDownloadById) { - sPendingDownloadById.put(mDownloadId, this); - } - } - - /** - * Cancels the current download. - */ - public synchronized void cancelDownload() { - mIsDownloadCancelled = true; - } - - /** - * @return tells if the current download has been cancelled. - */ - public synchronized boolean isDownloadCancelled() { - return mIsDownloadCancelled; - } - - /** - * @return the media URL. - */ - public String getUrl() { - return mUrl; - } - - /** - * Add an imageView to the list to refresh when the bitmap is downloaded. - * - * @param imageView an image view instance to refresh. - */ - public void addImageView(ImageView imageView) { - mImageViewReferences.add(new WeakReference<>(imageView)); - } - - /** - * Set the default bitmap to use when the Url is unreachable. - * - * @param aBitmap the bitmap. - */ - public void setDefaultBitmap(Bitmap aBitmap) { - mDefaultBitmap = aBitmap; - } - - /** - * Add a download listener. - * - * @param listener the listener to add. - */ - public void addDownloadListener(IMXMediaDownloadListener listener) { - if (null != listener) { - mDownloadListeners.add(listener); - } - } - - /** - * Returns the download progress. - * - * @return the download progress - */ - public int getProgress() { - if (null != mDownloadStats) { - return mDownloadStats.mProgress; - } - - return -1; - } - - /** - * @return the download stats - */ - public IMXMediaDownloadListener.DownloadStats getDownloadStats() { - return mDownloadStats; - } - - /** - * @return true if the current task is an image one. - */ - private boolean isBitmapDownloadTask() { - return null != mMimeType && mMimeType.startsWith("image/"); - } - - /** - * Push the download progress. - * - * @param startDownloadTime the start download time. - */ - private void updateAndPublishProgress(long startDownloadTime) { - mDownloadStats.mElapsedTime = (int) ((System.currentTimeMillis() - startDownloadTime) / 1000); - - if (mDownloadStats.mFileSize > 0) { - if (mDownloadStats.mDownloadedSize >= mDownloadStats.mFileSize) { - mDownloadStats.mProgress = 99; - } else { - mDownloadStats.mProgress = (int) (mDownloadStats.mDownloadedSize * 100L / mDownloadStats.mFileSize); - } - } else { - mDownloadStats.mProgress = -1; - } - - // avoid zero div - if (System.currentTimeMillis() != startDownloadTime) { - mDownloadStats.mBitRate = (int) (mDownloadStats.mDownloadedSize * 1000L / (System.currentTimeMillis() - startDownloadTime) / 1024); - } else { - mDownloadStats.mBitRate = -1; - } - - if ((0 != mDownloadStats.mBitRate) && (mDownloadStats.mFileSize > 0) && (mDownloadStats.mFileSize > mDownloadStats.mDownloadedSize)) { - mDownloadStats.mEstimatedRemainingTime = (mDownloadStats.mFileSize - mDownloadStats.mDownloadedSize) / 1024 / mDownloadStats.mBitRate; - } else { - mDownloadStats.mEstimatedRemainingTime = -1; - } - - Log.d(LOG_TAG, "updateAndPublishProgress " + this + " : " + mDownloadStats.mProgress); - - publishProgress(); - } - - /** - * Download and decode media in background. - * - * @param params - * @return JsonElement if an error occurs - */ - @Override - protected JsonElement doInBackground(Void... params) { - JsonElement jsonElementResult = null; - - MatrixError defaultError = new MatrixError(); - defaultError.errcode = MatrixError.UNKNOWN; - - // Note: No need for access token here - - try { - URL url = new URL(mUrl); - Log.d(LOG_TAG, "MXMediaDownloadWorkerTask " + this + " starts"); - - mDownloadStats = new IMXMediaDownloadListener.DownloadStats(); - // don't known yet - mDownloadStats.mEstimatedRemainingTime = -1; - - InputStream stream = null; - - int filelen = -1; - HttpURLConnection connection = null; - - try { - connection = (HttpURLConnection) url.openConnection(); - - if (RestClient.getUserAgent() != null) { - connection.setRequestProperty("User-Agent", RestClient.getUserAgent()); - } - - if (mHsConfig != null && connection instanceof HttpsURLConnection) { - // Add SSL Socket factory. - HttpsURLConnection sslConn = (HttpsURLConnection) connection; - try { - Pair pair = CertUtil.INSTANCE.newPinnedSSLSocketFactory(mHsConfig); - sslConn.setSSLSocketFactory(pair.first); - sslConn.setHostnameVerifier(CertUtil.INSTANCE.newHostnameVerifier(mHsConfig)); - } catch (Exception e) { - Log.e(LOG_TAG, "doInBackground SSL exception " + e.getMessage(), e); - } - } - - // add a timeout to avoid infinite loading display. - float scale = (null != mNetworkConnectivityReceiver) ? mNetworkConnectivityReceiver.getTimeoutScale() : 1.0f; - connection.setReadTimeout((int) (DOWNLOAD_TIME_OUT * scale)); - - if (mIsAvScannerEnabled && null != mEncryptedFileInfo) { - // POST the encryption info to let the av scanner decrypt and scan the content. - connection.setRequestMethod("POST"); - connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8"); - connection.setDoOutput(true); - connection.setUseCaches(false); - - EncryptedMediaScanBody encryptedMediaScanBody = new EncryptedMediaScanBody(); - encryptedMediaScanBody.encryptedFileInfo = mEncryptedFileInfo; - - String data = JsonUtils.getCanonicalizedJsonString(encryptedMediaScanBody); - - // Encrypt the data, if antivirus server supports it - String publicServerKey = getAntivirusServerPublicKey(); - - if (publicServerKey == null) { - // Error - throw new Exception("Unable to get public key"); - } else if (!TextUtils.isEmpty(publicServerKey)) { - OlmPkEncryption olmPkEncryption = new OlmPkEncryption(); - - olmPkEncryption.setRecipientKey(publicServerKey); - - OlmPkMessage message = olmPkEncryption.encrypt(data); - - EncryptedMediaScanEncryptedBody encryptedMediaScanEncryptedBody = new EncryptedMediaScanEncryptedBody(); - encryptedMediaScanEncryptedBody.encryptedBodyFileInfo = new EncryptedBodyFileInfo(message); - - data = JsonUtils.getCanonicalizedJsonString(encryptedMediaScanEncryptedBody); - } - // Else: no public key on this server, do not encrypt data - - OutputStream outputStream = connection.getOutputStream(); - try { - outputStream.write(data.getBytes("UTF-8")); - } catch (Exception e) { - Log.e(LOG_TAG, "doInBackground Failed to serialize encryption info " + e.getMessage(), e); - } finally { - outputStream.close(); - } - } - - filelen = connection.getContentLength(); - stream = connection.getInputStream(); - } catch (Exception e) { - Log.e(LOG_TAG, "bitmapForURL : fail to open the connection " + e.getMessage(), e); - defaultError.error = e.getLocalizedMessage(); - - // In case of 403, revert the key - if (connection.getResponseCode() == 403 && mMediaScanRestClient != null) { - mMediaScanRestClient.resetServerPublicKey(); - } - - InputStream errorStream = connection.getErrorStream(); - - if (null != errorStream) { - try { - BufferedReader streamReader = new BufferedReader(new InputStreamReader(errorStream, "UTF-8")); - StringBuilder responseStrBuilder = new StringBuilder(); - - String inputStr; - - while ((inputStr = streamReader.readLine()) != null) { - responseStrBuilder.append(inputStr); - } - - jsonElementResult = new JsonParser().parse(responseStrBuilder.toString()); - } catch (Exception ee) { - Log.e(LOG_TAG, "bitmapForURL : Error parsing error " + ee.getMessage(), ee); - } - } - - // privacy - //Log.d(LOG_TAG, "MediaWorkerTask " + mUrl + " does not exist"); - Log.d(LOG_TAG, "MediaWorkerTask an url does not exist"); - - // If some medias are not found, - // do not try to reload them until the next application launch. - // We mark this url as unreachable. - // We can do this only if the av scanner is disabled or if the media is unencrypted, - // (because the same url is used for all encrypted media when the av scanner is enabled). - if (!mIsAvScannerEnabled || null == mEncryptedFileInfo) { - synchronized (sUnreachableUrls) { - sUnreachableUrls.add(mUrl); - } - } - } - - dispatchDownloadStart(); - - // failed to open the remote stream without having exception - if ((null == stream) && (null == jsonElementResult)) { - jsonElementResult = new JsonParser().parse("Cannot open " + mUrl); - - // if some medias are not found - // do not try to reload them until the next application launch. - // We mark this url as unreachable. - // We can do this only if the av scanner is disabled or if the media is unencrypted, - // (because the same url is used for all encrypted media when the av scanner is enabled). - if (!mIsAvScannerEnabled || null == mEncryptedFileInfo) { - synchronized (sUnreachableUrls) { - sUnreachableUrls.add(mUrl); - } - } - } - - // test if the download has not been cancelled - if (!isDownloadCancelled() && (null == jsonElementResult)) { - final long startDownloadTime = System.currentTimeMillis(); - - String filename = buildFileName(mDownloadId, mMimeType) + ".tmp"; - FileOutputStream fos = new FileOutputStream(new File(mDirectoryFile, filename)); - - mDownloadStats.mDownloadId = mDownloadId; - mDownloadStats.mProgress = 0; - mDownloadStats.mDownloadedSize = 0; - mDownloadStats.mFileSize = filelen; - mDownloadStats.mElapsedTime = 0; - mDownloadStats.mEstimatedRemainingTime = -1; - mDownloadStats.mBitRate = 0; - - // Publish progress every 100ms - final Timer refreshTimer = new Timer(); - - refreshTimer.scheduleAtFixedRate(new TimerTask() { - @Override - public void run() { - if (!mIsDone) { - updateAndPublishProgress(startDownloadTime); - } - } - }, new Date(), 100); - - try { - byte[] buf = new byte[DOWNLOAD_BUFFER_READ_SIZE]; - int len; - while (!isDownloadCancelled() && (len = stream.read(buf)) != -1) { - fos.write(buf, 0, len); - mDownloadStats.mDownloadedSize += len; - } - - if (!isDownloadCancelled()) { - mDownloadStats.mProgress = 100; - } - } catch (OutOfMemoryError outOfMemoryError) { - Log.e(LOG_TAG, "doInBackground: out of memory", outOfMemoryError); - defaultError.error = outOfMemoryError.getLocalizedMessage(); - } catch (Exception e) { - Log.e(LOG_TAG, "doInBackground fail to read image " + e.getMessage(), e); - defaultError.error = e.getLocalizedMessage(); - } - - mIsDone = true; - - close(stream); - fos.flush(); - fos.close(); - - refreshTimer.cancel(); - - if ((null != connection) && (connection instanceof HttpsURLConnection)) { - connection.disconnect(); - } - - // the file has been successfully downloaded - if (mDownloadStats.mProgress == 100) { - try { - File originalFile = new File(mDirectoryFile, filename); - String newFileName = buildFileName(mDownloadId, mMimeType); - File newFile = new File(mDirectoryFile, newFileName); - if (newFile.exists()) { - // Or you could throw here. - mApplicationContext.deleteFile(newFileName); - } - originalFile.renameTo(newFile); - } catch (Exception e) { - Log.e(LOG_TAG, "doInBackground : renaming error " + e.getMessage(), e); - defaultError.error = e.getLocalizedMessage(); - } - } - } - - if (mDownloadStats.mProgress == 100) { - Log.d(LOG_TAG, "The download " + this + " is done."); - } else { - if (null != jsonElementResult) { - Log.d(LOG_TAG, "The download " + this + " failed : mErrorAsJsonElement " + jsonElementResult.toString()); - } else { - Log.d(LOG_TAG, "The download " + this + " failed."); - } - } - } catch (Exception e) { - Log.e(LOG_TAG, "Unable to download media " + this, e); - defaultError.error = e.getMessage(); - } - - // build a JSON from the error - if (!TextUtils.isEmpty(defaultError.error)) { - jsonElementResult = JsonUtils.getGson(false).toJsonTree(defaultError); - } - - // remove the task from the loading one - synchronized (sPendingDownloadById) { - sPendingDownloadById.remove(mDownloadId); - } - - return jsonElementResult; - } - - /** - * Get the public key of the antivirus server - * - * @return either empty string if server does not provide the public key, null in case of error, or the public server key - */ - @Nullable - private String getAntivirusServerPublicKey() { - if (mMediaScanRestClient == null) { - // Error - Log.e(LOG_TAG, "Mandatory mMediaScanRestClient is null"); - return null; - } - - // Make async request sync with a CountDownLatch - // It is easier than adding a method to get the server public key synchronously with Call.execute() - final CountDownLatch latch = new CountDownLatch(1); - final String[] publicServerKey = new String[1]; - - mMediaScanRestClient.getServerPublicKey(new ApiCallback() { - @Override - public void onSuccess(String serverPublicKey) { - publicServerKey[0] = serverPublicKey; - latch.countDown(); - } - - @Override - public void onNetworkError(Exception e) { - latch.countDown(); - } - - @Override - public void onMatrixError(MatrixError e) { - latch.countDown(); - } - - @Override - public void onUnexpectedError(Exception e) { - latch.countDown(); - } - }); - - try { - latch.await(30, TimeUnit.SECONDS); - } catch (InterruptedException ie) { - - } - - return publicServerKey[0]; - } - - /** - * Close the stream. - * - * @param stream the stream to close. - */ - private void close(InputStream stream) { - try { - stream.close(); - } catch (Exception e) { - Log.e(LOG_TAG, "close error " + e.getMessage(), e); - } - } - - @Override - protected void onProgressUpdate(Void... aVoid) { - super.onProgressUpdate(); - dispatchOnDownloadProgress(mDownloadStats); - } - - // Once complete, see if ImageView is still around and set bitmap. - @Override - protected void onPostExecute(JsonElement jsonElementError) { - if (null != jsonElementError) { - dispatchOnDownloadError(jsonElementError); - } else if (isDownloadCancelled()) { - dispatchDownloadCancel(); - } else { - dispatchOnDownloadComplete(); - - // image download - // update the linked ImageViews. - if (isBitmapDownloadTask()) { - // retrieve the bitmap from the file s - if (!bitmapForURL(mApplicationContext, mDirectoryFile, mUrl, mDownloadId, mRotation, mMimeType, mEncryptedFileInfo, - new SimpleApiCallback() { - @Override - public void onSuccess(Bitmap bitmap) { - setBitmap((null == bitmap) ? mDefaultBitmap : bitmap); - } - })) { - setBitmap(mDefaultBitmap); - } - } - } - } - - /** - * Set the bitmap in a referenced imageview - * - * @param bitmap the bitmap - */ - private void setBitmap(Bitmap bitmap) { - // update the imageViews image - if (bitmap != null) { - for (WeakReference weakRef : mImageViewReferences) { - final ImageView imageView = weakRef.get(); - - if (imageView != null && TextUtils.equals(mDownloadId, (String) imageView.getTag())) { - imageView.setImageBitmap(bitmap); - } - } - } - } - - - //============================================================================================================== - // Dispatchers - //============================================================================================================== - - /** - * Dispatch start event to the callbacks. - */ - private void dispatchDownloadStart() { - for (IMXMediaDownloadListener callback : mDownloadListeners) { - try { - callback.onDownloadStart(mDownloadId); - } catch (Exception e) { - Log.e(LOG_TAG, "dispatchDownloadStart error " + e.getMessage(), e); - } - } - } - - /** - * Dispatch stats update to the callbacks. - * - * @param stats the new stats value - */ - private void dispatchOnDownloadProgress(IMXMediaDownloadListener.DownloadStats stats) { - for (IMXMediaDownloadListener callback : mDownloadListeners) { - try { - callback.onDownloadProgress(mDownloadId, stats); - } catch (Exception e) { - Log.e(LOG_TAG, "dispatchOnDownloadProgress error " + e.getMessage(), e); - } - } - } - - /** - * Dispatch error message. - * - * @param jsonElement the Json error - */ - private void dispatchOnDownloadError(JsonElement jsonElement) { - for (IMXMediaDownloadListener callback : mDownloadListeners) { - try { - callback.onDownloadError(mDownloadId, jsonElement); - } catch (Exception e) { - Log.e(LOG_TAG, "dispatchOnDownloadError error " + e.getMessage(), e); - } - } - } - - /** - * Dispatch end of download - */ - private void dispatchOnDownloadComplete() { - for (IMXMediaDownloadListener callback : mDownloadListeners) { - try { - callback.onDownloadComplete(mDownloadId); - } catch (Exception e) { - Log.e(LOG_TAG, "dispatchOnDownloadComplete error " + e.getMessage(), e); - } - } - } - - /** - * Dispatch download cancel - */ - private void dispatchDownloadCancel() { - for (IMXMediaDownloadListener callback : mDownloadListeners) { - try { - callback.onDownloadCancel(mDownloadId); - } catch (Exception e) { - Log.e(LOG_TAG, "dispatchDownloadCancel error " + e.getMessage(), e); - } - } - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/db/MXMediaUploadWorkerTask.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/db/MXMediaUploadWorkerTask.java deleted file mode 100644 index 1adf7e91..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/db/MXMediaUploadWorkerTask.java +++ /dev/null @@ -1,570 +0,0 @@ -/* - * Copyright 2015 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.db; - -import android.os.AsyncTask; -import android.util.Pair; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.DataOutputStream; -import java.io.EOFException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Timer; -import java.util.TimerTask; - -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.X509TrustManager; - -import im.vector.matrix.android.internal.legacy.RestClient; -import im.vector.matrix.android.internal.legacy.listeners.IMXMediaUploadListener; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.model.ContentResponse; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.util.ContentManager; -import im.vector.matrix.android.internal.legacy.util.JsonUtils; -import im.vector.matrix.android.internal.legacy.util.Log; -import im.vector.matrix.android.internal.network.ssl.CertUtil; - -/** - * Private AsyncTask used to upload files. - */ -public class MXMediaUploadWorkerTask extends AsyncTask { - - private static final String LOG_TAG = MXMediaUploadWorkerTask.class.getSimpleName(); - - // upload ID -> task - private static final Map mPendingUploadByUploadId = new HashMap<>(); - - // progress listener - private final List mUploadListeners = new ArrayList<>(); - - // the upload stats - private IMXMediaUploadListener.UploadStats mUploadStats; - - // the media mimeType - private final String mMimeType; - - // the media to upload - private final InputStream mContentStream; - - // its unique identifier - private final String mUploadId; - - // store the server response to provide it the listeners - private String mResponseFromServer; - - // tells if the current upload has been cancelled. - private boolean mIsCancelled; - - /** - * Tells if the upload has been completed - */ - private boolean mIsDone; - - // upload const - private static final int UPLOAD_BUFFER_READ_SIZE = 1024 * 32; - - // dummy ApiCallback uses to be warned when the upload must be declared as "undeliverable". - private final ApiCallback mApiCallback = new ApiCallback() { - @Override - public void onSuccess(Object info) { - } - - @Override - public void onNetworkError(Exception e) { - } - - @Override - public void onMatrixError(MatrixError e) { - } - - @Override - public void onUnexpectedError(Exception e) { - dispatchResult(mResponseFromServer); - } - }; - - // the upload server HTTP response code - private int mResponseCode = -1; - - // the media file name - private String mFilename; - - // the content manager - private final ContentManager mContentManager; - - /** - * Check if there is a pending download for the url. - * - * @param uploadId The id to check the existence - * @return the dedicated BitmapWorkerTask if it exists. - */ - public static MXMediaUploadWorkerTask getMediaUploadWorkerTask(String uploadId) { - if (uploadId != null) { - MXMediaUploadWorkerTask task = null; - synchronized (mPendingUploadByUploadId) { - if (mPendingUploadByUploadId.containsKey(uploadId)) { - task = mPendingUploadByUploadId.get(uploadId); - } - } - return task; - } - - return null; - } - - /** - * Cancel the pending uploads. - */ - public static void cancelPendingUploads() { - Collection tasks = mPendingUploadByUploadId.values(); - - // cancels the running task - for (MXMediaUploadWorkerTask task : tasks) { - try { - task.cancelUpload(); - task.cancel(true); - } catch (Exception e) { - Log.e(LOG_TAG, "cancelPendingUploads " + e.getMessage(), e); - } - } - - mPendingUploadByUploadId.clear(); - } - - /** - * Constructor - * - * @param contentManager the content manager - * @param contentStream the stream to upload - * @param mimeType the mime type - * @param uploadId the upload id - * @param filename the dest filename - * @param listener the upload listener - */ - public MXMediaUploadWorkerTask(ContentManager contentManager, - InputStream contentStream, - String mimeType, - String uploadId, - String filename, - IMXMediaUploadListener listener) { - if (contentStream.markSupported()) { - try { - contentStream.reset(); - } catch (Exception e) { - Log.e(LOG_TAG, "MXMediaUploadWorkerTask " + e.getMessage(), e); - } - } else { - Log.w(LOG_TAG, "Warning, reset() is not supported for this stream"); - } - - - mContentManager = contentManager; - mContentStream = contentStream; - mMimeType = mimeType; - mUploadId = uploadId; - mFilename = filename; - - addListener(listener); - - if (null != uploadId) { - mPendingUploadByUploadId.put(uploadId, this); - } - } - - /** - * Add an upload listener - * - * @param aListener the listener to add. - */ - public void addListener(IMXMediaUploadListener aListener) { - if (null != aListener && mUploadListeners.indexOf(aListener) < 0) { - mUploadListeners.add(aListener); - } - } - - /** - * @return the upload progress - */ - public int getProgress() { - if (null != mUploadStats) { - return mUploadStats.mProgress; - } - return -1; - } - - /** - * @return the upload stats - */ - public IMXMediaUploadListener.UploadStats getStats() { - return mUploadStats; - } - - /** - * @return true if the current upload has been cancelled. - */ - private synchronized boolean isUploadCancelled() { - return mIsCancelled; - } - - /** - * Cancel the current upload. - */ - public synchronized void cancelUpload() { - mIsCancelled = true; - } - - /** - * refresh the progress info - */ - private void publishProgress(long startUploadTime) { - mUploadStats.mElapsedTime = (int) ((System.currentTimeMillis() - startUploadTime) / 1000); - - if (0 != mUploadStats.mFileSize) { - // Uploading data is 90% of the job - // the other 10% is the end of the connection related actions - mUploadStats.mProgress = (int) (((long) mUploadStats.mUploadedSize) * 96 / mUploadStats.mFileSize); - } - - // avoid zero div - if (System.currentTimeMillis() != startUploadTime) { - mUploadStats.mBitRate = (int) (((long) mUploadStats.mUploadedSize) * 1000 / (System.currentTimeMillis() - startUploadTime) / 1024); - } else { - mUploadStats.mBitRate = 0; - } - - if (0 != mUploadStats.mBitRate) { - mUploadStats.mEstimatedRemainingTime = (mUploadStats.mFileSize - mUploadStats.mUploadedSize) / 1024 / mUploadStats.mBitRate; - } else { - mUploadStats.mEstimatedRemainingTime = -1; - } - - publishProgress(); - } - - @Override - protected String doInBackground(Void... params) { - HttpURLConnection conn; - DataOutputStream dos; - - mResponseCode = -1; - - int bytesRead, bytesAvailable; - int totalWritten, totalSize; - int bufferSize; - byte[] buffer; - - String serverResponse = null; - - String urlString = mContentManager.getHsConfig().getHomeServerUri().toString() + ContentManager.URI_PREFIX_CONTENT_API + "upload"; - - if (null != mFilename) { - try { - String utf8Filename = URLEncoder.encode(mFilename, "utf-8"); - urlString += "?filename=" + utf8Filename; - } catch (Exception e) { - Log.e(LOG_TAG, "doInBackground " + e.getMessage(), e); - } - } - - try { - URL url = new URL(urlString); - - conn = (HttpURLConnection) url.openConnection(); - if (RestClient.getUserAgent() != null) { - conn.setRequestProperty("User-Agent", RestClient.getUserAgent()); - } - conn.setRequestProperty("Authorization", "Bearer " + mContentManager.getCredentials().getAccessToken()); - conn.setDoInput(true); - conn.setDoOutput(true); - conn.setUseCaches(false); - conn.setRequestMethod("POST"); - - if (conn instanceof HttpsURLConnection) { - // Add SSL Socket factory. - HttpsURLConnection sslConn = (HttpsURLConnection) conn; - try { - Pair pair = CertUtil.INSTANCE.newPinnedSSLSocketFactory(mContentManager.getHsConfig()); - sslConn.setSSLSocketFactory(pair.first); - sslConn.setHostnameVerifier(CertUtil.INSTANCE.newHostnameVerifier(mContentManager.getHsConfig())); - } catch (Exception e) { - Log.e(LOG_TAG, "sslConn " + e.getMessage(), e); - } - } - - conn.setRequestProperty("Content-Type", mMimeType); - conn.setRequestProperty("Content-Length", Integer.toString(mContentStream.available())); - // avoid caching data before really sending them. - conn.setFixedLengthStreamingMode(mContentStream.available()); - - conn.connect(); - - dos = new DataOutputStream(conn.getOutputStream()); - - // create a buffer of maximum size - totalSize = bytesAvailable = mContentStream.available(); - totalWritten = 0; - bufferSize = Math.min(bytesAvailable, UPLOAD_BUFFER_READ_SIZE); - buffer = new byte[bufferSize]; - - mUploadStats = new IMXMediaUploadListener.UploadStats(); - mUploadStats.mUploadId = mUploadId; - mUploadStats.mProgress = 0; - mUploadStats.mUploadedSize = 0; - mUploadStats.mFileSize = totalSize; - mUploadStats.mElapsedTime = 0; - mUploadStats.mEstimatedRemainingTime = -1; - mUploadStats.mBitRate = 0; - - final long startUploadTime = System.currentTimeMillis(); - - Log.d(LOG_TAG, "doInBackground : start Upload (" + totalSize + " bytes)"); - - // read file and write it into form... - bytesRead = mContentStream.read(buffer, 0, bufferSize); - - dispatchOnUploadStart(); - - final Timer refreshTimer = new Timer(); - - // Publish progress every 100ms - refreshTimer.scheduleAtFixedRate(new TimerTask() { - @Override - public void run() { - if (!mIsDone) { - publishProgress(startUploadTime); - } - } - }, new Date(), 100); - - while ((bytesRead > 0) && !isUploadCancelled()) { - dos.write(buffer, 0, bytesRead); - totalWritten += bytesRead; - bytesAvailable = mContentStream.available(); - bufferSize = Math.min(bytesAvailable, UPLOAD_BUFFER_READ_SIZE); - - Log.d(LOG_TAG, "doInBackground : totalWritten " + totalWritten + " / totalSize " + totalSize); - mUploadStats.mUploadedSize = totalWritten; - bytesRead = mContentStream.read(buffer, 0, bufferSize); - } - mIsDone = true; - - refreshTimer.cancel(); - - if (!isUploadCancelled()) { - mUploadStats.mProgress = 96; - publishProgress(startUploadTime); - dos.flush(); - mUploadStats.mProgress = 97; - publishProgress(startUploadTime); - dos.close(); - mUploadStats.mProgress = 98; - publishProgress(startUploadTime); - - try { - // Read the SERVER RESPONSE - mResponseCode = conn.getResponseCode(); - } catch (EOFException eofEx) { - mResponseCode = HttpURLConnection.HTTP_INTERNAL_ERROR; - } - - mUploadStats.mProgress = 99; - publishProgress(startUploadTime); - - Log.d(LOG_TAG, "doInBackground : Upload is done with response code " + mResponseCode); - - InputStream is; - - if (mResponseCode == HttpURLConnection.HTTP_OK) { - is = conn.getInputStream(); - } else { - is = conn.getErrorStream(); - } - - int ch; - StringBuffer b = new StringBuffer(); - while ((ch = is.read()) != -1) { - b.append((char) ch); - } - serverResponse = b.toString(); - is.close(); - - // the server should provide an error description - if (mResponseCode != HttpURLConnection.HTTP_OK) { - try { - JSONObject responseJSON = new JSONObject(serverResponse); - serverResponse = responseJSON.getString("error"); - } catch (JSONException e) { - Log.e(LOG_TAG, "doInBackground : Error parsing " + e.getMessage(), e); - } - } - } else { - dos.flush(); - dos.close(); - } - - if (null != conn) { - conn.disconnect(); - } - } catch (Exception e) { - serverResponse = e.getLocalizedMessage(); - Log.e(LOG_TAG, "doInBackground ; failed with error " + e.getClass() + " - " + e.getMessage(), e); - } - - mResponseFromServer = serverResponse; - - return serverResponse; - } - - @Override - protected void onProgressUpdate(Void... aVoid) { - super.onProgressUpdate(); - - Log.d(LOG_TAG, "Upload " + this + " : " + mUploadStats.mProgress); - - dispatchOnUploadProgress(mUploadStats); - } - - /** - * Dispatch the result to the callbacks - * - * @param serverResponse the server response - */ - private void dispatchResult(final String serverResponse) { - if (null != mUploadId) { - mPendingUploadByUploadId.remove(mUploadId); - } - - mContentManager.getUnsentEventsManager().onEventSent(mApiCallback); - - // close the source stream - try { - mContentStream.close(); - } catch (Exception e) { - Log.e(LOG_TAG, "dispatchResult " + e.getMessage(), e); - } - - if (isUploadCancelled()) { - dispatchOnUploadCancel(); - } else { - ContentResponse uploadResponse = (mResponseCode != 200 || serverResponse == null) ? null : JsonUtils.toContentResponse(serverResponse); - - if (null == uploadResponse || null == uploadResponse.contentUri) { - dispatchOnUploadError(mResponseCode, serverResponse); - } else { - dispatchOnUploadComplete(uploadResponse.contentUri); - } - } - } - - @Override - protected void onPostExecute(final String serverResponseMessage) { - // do not call the callback if cancelled. - if (!isCancelled()) { - dispatchResult(serverResponseMessage); - } - } - - //============================================================================================================== - // Dispatchers - //============================================================================================================== - - /** - * Dispatch Upload start - */ - private void dispatchOnUploadStart() { - for (IMXMediaUploadListener listener : mUploadListeners) { - try { - listener.onUploadStart(mUploadId); - } catch (Exception e) { - Log.e(LOG_TAG, "dispatchOnUploadStart failed " + e.getMessage(), e); - } - } - } - - /** - * Dispatch Upload start - * - * @param stats the upload stats - */ - private void dispatchOnUploadProgress(IMXMediaUploadListener.UploadStats stats) { - for (IMXMediaUploadListener listener : mUploadListeners) { - try { - listener.onUploadProgress(mUploadId, stats); - } catch (Exception e) { - Log.e(LOG_TAG, "dispatchOnUploadProgress failed " + e.getMessage(), e); - } - } - } - - /** - * Dispatch Upload cancel. - */ - private void dispatchOnUploadCancel() { - for (IMXMediaUploadListener listener : mUploadListeners) { - try { - listener.onUploadCancel(mUploadId); - } catch (Exception e) { - Log.e(LOG_TAG, "listener failed " + e.getMessage(), e); - } - } - } - - /** - * Dispatch Upload error. - * - * @param serverResponseCode the server response code. - * @param serverErrorMessage the server error message - */ - private void dispatchOnUploadError(int serverResponseCode, String serverErrorMessage) { - for (IMXMediaUploadListener listener : mUploadListeners) { - try { - listener.onUploadError(mUploadId, serverResponseCode, serverErrorMessage); - } catch (Exception e) { - Log.e(LOG_TAG, "dispatchOnUploadError failed " + e.getMessage(), e); - } - } - } - - /** - * Dispatch Upload complete. - * - * @param contentUri the media uri. - */ - private void dispatchOnUploadComplete(String contentUri) { - for (IMXMediaUploadListener listener : mUploadListeners) { - try { - listener.onUploadComplete(mUploadId, contentUri); - } catch (Exception e) { - Log.e(LOG_TAG, "dispatchOnUploadComplete failed " + e.getMessage(), e); - } - } - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/db/MXMediasCache.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/db/MXMediasCache.java deleted file mode 100644 index ac42c643..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/db/MXMediasCache.java +++ /dev/null @@ -1,1522 +0,0 @@ -/* - * Copyright 2015 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.db; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.media.ExifInterface; -import android.net.Uri; -import android.os.AsyncTask; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.support.annotation.Nullable; -import android.text.TextUtils; -import android.webkit.MimeTypeMap; -import android.widget.ImageView; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Set; -import java.util.concurrent.RejectedExecutionException; - -import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig; -import im.vector.matrix.android.internal.legacy.crypto.MXEncryptedAttachments; -import im.vector.matrix.android.internal.legacy.listeners.IMXMediaDownloadListener; -import im.vector.matrix.android.internal.legacy.listeners.IMXMediaUploadListener; -import im.vector.matrix.android.internal.legacy.listeners.MXMediaDownloadListener; -import im.vector.matrix.android.internal.legacy.network.NetworkConnectivityReceiver; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.SimpleApiCallback; -import im.vector.matrix.android.internal.legacy.rest.client.MediaScanRestClient; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.EncryptedFileInfo; -import im.vector.matrix.android.internal.legacy.util.ContentManager; -import im.vector.matrix.android.internal.legacy.util.ContentUtils; -import im.vector.matrix.android.internal.legacy.util.Log; -import im.vector.matrix.android.internal.legacy.util.MXOsHandler; - -public class MXMediasCache { - - private static final String LOG_TAG = MXMediasCache.class.getSimpleName(); - - /** - * The medias folders. - */ - // Put the previous folders used for cache here. Every time the cache management change (change of id format, etc.), - // append the current cache folder to this list, and change value of MXMEDIA_STORE_FOLDER (typically increment the value) - private static final List sPreviousMediaCacheFolders = Arrays.asList( - "MXMediaStore", - "MXMediaStore2" - ); - - private static final String MXMEDIA_STORE_FOLDER = "MXMediaStore3"; - private static final String MXMEDIA_STORE_MEMBER_THUMBNAILS_FOLDER = "MXMemberThumbnailsStore"; - private static final String MXMEDIA_STORE_IMAGES_FOLDER = "Images"; - private static final String MXMEDIA_STORE_OTHERS_FOLDER = "Others"; - private static final String MXMEDIA_STORE_TMP_FOLDER = "tmp"; - private static final String MXMEDIA_STORE_SHARE_FOLDER = "share"; - - /** - * The content manager - */ - private ContentManager mContentManager; - - /** - * The medias folders list. - */ - private File mMediasFolderFile; - private File mImagesFolderFile; - private File mOthersFolderFile; - private File mThumbnailsFolderFile; - - // This folder will contain decrypted media files - private File mTmpFolderFile; - - // This folder will contain decrypted media files, for file sharing - private File mShareFolderFile; - - // track the network updates - private final NetworkConnectivityReceiver mNetworkConnectivityReceiver; - - // the background thread - static HandlerThread mDecryptingHandlerThread = null; - static MXOsHandler mDecryptingHandler = null; - static android.os.Handler mUIHandler = null; - - private MediaScanRestClient mMediaScanRestClient; - - /** - * Constructor - * - * @param contentManager the content manager. - * @param networkConnectivityReceiver the network connectivity receiver - * @param userID the account user Id. - * @param context the context - */ - public MXMediasCache(ContentManager contentManager, NetworkConnectivityReceiver networkConnectivityReceiver, String userID, Context context) { - mContentManager = contentManager; - mNetworkConnectivityReceiver = networkConnectivityReceiver; - - File mediaBaseFolderFile; - - // Clear previous cache - for (String previousMediaCacheFolder : sPreviousMediaCacheFolders) { - mediaBaseFolderFile = new File(context.getApplicationContext().getFilesDir(), previousMediaCacheFolder); - - if (mediaBaseFolderFile.exists()) { - ContentUtils.deleteDirectory(mediaBaseFolderFile); - } - } - - mediaBaseFolderFile = new File(context.getApplicationContext().getFilesDir(), MXMEDIA_STORE_FOLDER); - - if (!mediaBaseFolderFile.exists()) { - mediaBaseFolderFile.mkdirs(); - } - - // create the dir tree - mMediasFolderFile = new File(mediaBaseFolderFile, userID); - mImagesFolderFile = new File(mMediasFolderFile, MXMEDIA_STORE_IMAGES_FOLDER); - mOthersFolderFile = new File(mMediasFolderFile, MXMEDIA_STORE_OTHERS_FOLDER); - mTmpFolderFile = new File(mMediasFolderFile, MXMEDIA_STORE_TMP_FOLDER); - - if (mTmpFolderFile.exists()) { - ContentUtils.deleteDirectory(mTmpFolderFile); - } - mTmpFolderFile.mkdirs(); - - mShareFolderFile = new File(mMediasFolderFile, MXMEDIA_STORE_SHARE_FOLDER); - - if (mShareFolderFile.exists()) { - ContentUtils.deleteDirectory(mShareFolderFile); - } - mShareFolderFile.mkdirs(); - - mThumbnailsFolderFile = new File(mediaBaseFolderFile, MXMEDIA_STORE_MEMBER_THUMBNAILS_FOLDER); - - // use the same thread for all the sessions - if (null == mDecryptingHandlerThread) { - mDecryptingHandlerThread = new HandlerThread("MXMediaDecryptingBackgroundThread", Thread.MIN_PRIORITY); - mDecryptingHandlerThread.start(); - mDecryptingHandler = new MXOsHandler(mDecryptingHandlerThread.getLooper()); - mUIHandler = new Handler(Looper.getMainLooper()); - } - } - - /** - * Returns the mediasFolder files. - * Creates it if it does not exist - * - * @return the medias folder file. - */ - private File getMediasFolderFile() { - if (!mMediasFolderFile.exists()) { - mMediasFolderFile.mkdirs(); - } - - return mMediasFolderFile; - } - - /** - * Returns the folder file for a dedicated mimetype. - * Creates it if it does not exist - * - * @param mimeType the media mimetype. - * @return the folder file. - */ - private File getFolderFile(String mimeType) { - File file; - - // - if ((null == mimeType) || mimeType.startsWith("image/")) { - file = mImagesFolderFile; - } else { - file = mOthersFolderFile; - } - - if (!file.exists()) { - file.mkdirs(); - } - - return file; - } - - /** - * Returns the thumbnails folder. - * Creates it if it does not exist - * - * @return the thumbnails folder file. - */ - private File getThumbnailsFolderFile() { - if (!mThumbnailsFolderFile.exists()) { - mThumbnailsFolderFile.mkdirs(); - } - - return mThumbnailsFolderFile; - } - - /** - * Compute the medias cache size - * - * @param context the context - * @param callback the asynchronous callback - */ - public static void getCachesSize(final Context context, final ApiCallback callback) { - AsyncTask task = new AsyncTask() { - @Override - protected Long doInBackground(Void... params) { - return ContentUtils.getDirectorySize(context, - new File(context.getApplicationContext().getFilesDir(), MXMEDIA_STORE_FOLDER), - 1); - } - - @Override - protected void onPostExecute(Long result) { - Log.d(LOG_TAG, "## getCachesSize() : " + result); - if (null != callback) { - callback.onSuccess(result); - } - } - }; - try { - task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } catch (Exception e) { - Log.e(LOG_TAG, "## getCachesSize() : failed " + e.getMessage(), e); - task.cancel(true); - } - } - - /** - * Remove medias older than ts - * - * @param ts the ts - * @param filePathToKeep set of files to keep - * @return length of deleted files - */ - public long removeMediasBefore(long ts, Set filePathToKeep) { - long length = 0; - - length += removeMediasBefore(getMediasFolderFile(), ts, filePathToKeep); - length += removeMediasBefore(getThumbnailsFolderFile(), ts, filePathToKeep); - - return length; - } - - /** - * Recursive method to remove older messages - * - * @param folder the base folder - * @param aTs the ts - * @param filePathToKeep set of files to keep - * @return length of deleted files - */ - private long removeMediasBefore(File folder, long aTs, Set filePathToKeep) { - long length = 0; - File[] files = folder.listFiles(); - - if (null != files) { - for (int i = 0; i < files.length; i++) { - File file = files[i]; - - if (!file.isDirectory()) { - - if (!filePathToKeep.contains(file.getPath())) { - long ts = ContentUtils.getLastAccessTime(file); - if (ts < aTs) { - length += file.length(); - file.delete(); - } - } - } else { - length += removeMediasBefore(file, aTs, filePathToKeep); - } - } - } - - return length; - } - - /** - * Clear the medias caches. - */ - public void clear() { - ContentUtils.deleteDirectory(getMediasFolderFile()); - - ContentUtils.deleteDirectory(mThumbnailsFolderFile); - - // clear the media cache - MXMediaDownloadWorkerTask.clearBitmapsCache(); - - // cancel pending uploads. - MXMediaUploadWorkerTask.cancelPendingUploads(); - } - - /** - * The thumbnails cached is not cleared when logging out a session - * because many sessions share the same thumbnails. - * This method must be called when performing an application logout - * i.e. logging out of all sessions. - * - * @param applicationContext the application context - */ - public static void clearThumbnailsCache(Context applicationContext) { - ContentUtils.deleteDirectory(new File(new File(applicationContext.getApplicationContext().getFilesDir(), MXMediasCache.MXMEDIA_STORE_FOLDER), - MXMEDIA_STORE_MEMBER_THUMBNAILS_FOLDER)); - } - - /** - * Provide the thumbnail file. - * - * @param url the thumbnail url/ - * @param size the thumbnail size. - * @return the File if it exits. - */ - @Nullable - public File thumbnailCacheFile(String url, int size) { - // We use the download task id to define a cache id - String thumbnailCacheId = mContentManager.downloadTaskIdForMatrixMediaContent(url); - - if (null != thumbnailCacheId) { - if (size > 0) { - thumbnailCacheId += "_w_" + size + "_h_" + size; - } - String filename = MXMediaDownloadWorkerTask.buildFileName(thumbnailCacheId, "image/jpeg"); - - try { - File file = new File(getThumbnailsFolderFile(), filename); - - if (file.exists()) { - return file; - } - } catch (Exception e) { - Log.e(LOG_TAG, "thumbnailCacheFile failed " + e.getMessage(), e); - } - } - - return null; - } - - /** - * Return the cache file name for a media defined by its URL and its mime type. - * - * @param url the media URL - * @param width the media width - * @param height the media height - * @param mimeType the media mime type - * @return the media file it is found - */ - @Nullable - private File mediaCacheFile(String url, int width, int height, String mimeType) { - // sanity check - if (null == url) { - return null; - } - - String filename; - if (url.startsWith("file:")) { - filename = url; - } else { - // We use the download task id to define a cache id - String cacheId = mContentManager.downloadTaskIdForMatrixMediaContent(url); - if (null != cacheId) { - if ((width > 0) && (height > 0)) { - cacheId += "_w_" + width + "_h_" + height; - } - filename = MXMediaDownloadWorkerTask.buildFileName(cacheId, mimeType); - } else { - return null; - } - } - - try { - // already a local file - if (filename.startsWith("file:")) { - Uri uri = Uri.parse(filename); - filename = uri.getLastPathSegment(); - } - - File file = new File(getFolderFile(mimeType), filename); - - if (file.exists()) { - return file; - } - - } catch (Exception e) { - Log.e(LOG_TAG, "mediaCacheFile failed " + e.getMessage(), e); - } - - return null; - } - - /** - * Tells if a media is cached - * - * @param url the url - * @param mimeType the mimetype - * @return true if the media is cached - */ - public boolean isMediaCached(String url, String mimeType) { - return isMediaCached(url, -1, -1, mimeType); - } - - /** - * Tells if a media is cached - * - * @param url the media URL - * @param width the media width - * @param height the media height - * @param mimeType the media mime type - * @return the media file is cached - */ - public boolean isMediaCached(String url, int width, int height, String mimeType) { - return null != mediaCacheFile(url, width, height, mimeType); - } - - /** - * Create a temporary decrypted copy of a media. - * It must be released when it is not used anymore with clearTmpDecryptedMediaCache(). - * - * @param url the media url - * @param mimeType the media mime type - * @param encryptedFileInfo the encryption information - * @param callback the asynchronous callback - * @return true if the file is cached - */ - public boolean createTmpDecryptedMediaFile(String url, - String mimeType, - EncryptedFileInfo encryptedFileInfo, - ApiCallback callback) { - return createTmpDecryptedMediaFile(url, - -1, - -1, - mimeType, - encryptedFileInfo, - callback); - } - - /** - * Create a temporary decrypted copy of a media. - * It must be released when it is not used anymore with clearTmpDecryptedMediaCache(). - * - * @param url the media URL - * @param width the media width - * @param height the media height - * @param mimeType the media mime type - * @param encryptedFileInfo the encryption information - * @param callback the asynchronous callback - * @return true if the file is cached - */ - public boolean createTmpDecryptedMediaFile(String url, - int width, - int height, - String mimeType, - final EncryptedFileInfo encryptedFileInfo, - final ApiCallback callback) { - final File file = mediaCacheFile(url, width, height, mimeType); - - if (null != file) { - mDecryptingHandler.post(new Runnable() { - @Override - public void run() { - final File tmpFile = new File(mTmpFolderFile, file.getName()); - - // create it only if it does not exist yet - if (!tmpFile.exists()) { - try { - InputStream fis = new FileInputStream(file); - - if (null != encryptedFileInfo) { - InputStream is = MXEncryptedAttachments.decryptAttachment(fis, encryptedFileInfo); - fis.close(); - fis = is; - } - - FileOutputStream fos = new FileOutputStream(tmpFile); - byte[] buf = new byte[2048]; - int len; - while ((len = fis.read(buf)) != -1) { - fos.write(buf, 0, len); - } - - fis.close(); - fos.close(); - } catch (Exception e) { - Log.e(LOG_TAG, "## createTmpDecryptedMediaFile() failed " + e.getMessage(), e); - } - } - - mUIHandler.post(new Runnable() { - @Override - public void run() { - callback.onSuccess(tmpFile); - } - }); - } - }); - } - return (null != file); - } - - /** - * Clear the temporary decrypted media cache folder - */ - public void clearTmpDecryptedMediaCache() { - Log.d(LOG_TAG, "clearTmpDecryptedMediaCache()"); - - if (mTmpFolderFile.exists()) { - ContentUtils.deleteDirectory(mTmpFolderFile); - } - - if (!mTmpFolderFile.exists()) { - mTmpFolderFile.mkdirs(); - } - } - - /** - * Move a decrypted media file to the /share folder, to avoid this file to be deleted if in the /tmp folder - * - * @param fileToMove The file to move - * @param filename the filename, without path - * @return The copied file in the Share folder location - */ - public File moveToShareFolder(final File fileToMove, - final String filename) { - File dstFile = new File(mShareFolderFile, filename); - - if (dstFile.exists()) { - if (!dstFile.delete()) { - Log.w(LOG_TAG, "Unable to delete file"); - } - } - - if (!fileToMove.renameTo(dstFile)) { - Log.w(LOG_TAG, "Unable to rename file"); - - // Return the original file - return fileToMove; - } - - return dstFile; - } - - /** - * Clear the temporary shared decrypted media cache folder - */ - public void clearShareDecryptedMediaCache() { - Log.d(LOG_TAG, "clearShareDecryptedMediaCache()"); - - if (mShareFolderFile.exists()) { - ContentUtils.deleteDirectory(mShareFolderFile); - } - - if (!mShareFolderFile.exists()) { - mShareFolderFile.mkdirs(); - } - } - - /** - * Save a bitmap to the local cache - * it could be used for unsent media to allow them to be resent. - * - * @param bitmap the bitmap to save - * @param defaultFileName the filename is provided, if null, a filename will be generated - * @return the media cache URL - */ - public String saveBitmap(Bitmap bitmap, String defaultFileName) { - String filename = "file" + System.currentTimeMillis() + ".jpg"; - String cacheURL = null; - - try { - if (null != defaultFileName) { - File file = new File(getFolderFile(null), defaultFileName); - file.delete(); - - filename = Uri.fromFile(file).getLastPathSegment(); - } - - File file = new File(getFolderFile(null), filename); - FileOutputStream fos = new FileOutputStream(file.getPath()); - - // We got an java.lang.IllegalStateException: Can't compress a recycled bitmap - if (bitmap.isRecycled()) { - Log.w(LOG_TAG, "Trying to compress a recycled Bitmap. Create a copy first."); - bitmap = Bitmap.createBitmap(bitmap); - } - - bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos); - - fos.flush(); - fos.close(); - - cacheURL = Uri.fromFile(file).toString(); - } catch (Exception e) { - Log.e(LOG_TAG, "saveBitmap failed " + e.getMessage(), e); - } - - return cacheURL; - } - - /** - * Save a media to the local cache - * it could be used for unsent media to allow them to be resent. - * - * @param stream the file stream to save - * @param defaultFileName the filename is provided, if null, a filename will be generated - * @param mimeType the mime type. - * @return the media cache URL - */ - public String saveMedia(InputStream stream, String defaultFileName, String mimeType) { - String filename = defaultFileName; - - if (null == filename) { - filename = "file" + System.currentTimeMillis(); - - if (null != mimeType) { - String extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType); - - if (null == extension) { - if (mimeType.lastIndexOf("/") >= 0) { - extension = mimeType.substring(mimeType.lastIndexOf("/") + 1); - } - } - - if (!TextUtils.isEmpty(extension)) { - filename += "." + extension; - } - } - } - - String cacheURL = null; - - try { - File file = new File(getFolderFile(mimeType), filename); - - // if the file exits, delete it - if (file.exists()) { - file.delete(); - } - - FileOutputStream fos = new FileOutputStream(file.getPath()); - - try { - byte[] buf = new byte[1024 * 32]; - - int len; - while ((len = stream.read(buf)) != -1) { - fos.write(buf, 0, len); - } - } catch (Exception e) { - Log.e(LOG_TAG, "saveMedia failed " + e.getMessage(), e); - } - - fos.flush(); - fos.close(); - stream.close(); - - cacheURL = Uri.fromFile(file).toString(); - } catch (Exception e) { - Log.e(LOG_TAG, "saveMedia failed " + e.getMessage(), e); - - } - - return cacheURL; - } - - /** - * Replace a media cache by a file content. - * - * @param mediaUrl the mediaUrl - * @param mimeType the mimeType. - * @param fileUrl the file which replaces the cached media. - */ - public void saveFileMediaForUrl(String mediaUrl, - String fileUrl, - String mimeType) { - saveFileMediaForUrl(mediaUrl, - fileUrl, - -1, - -1, - mimeType); - } - - /** - * Replace a media cache by a file content. - * MediaUrl is the same model as the one used in loadBitmap. - * - * @param mediaUrl the mediaUrl - * @param fileUrl the file which replaces the cached media. - * @param width the expected image width - * @param height the expected image height - * @param mimeType the mimeType. - */ - public void saveFileMediaForUrl(String mediaUrl, - String fileUrl, - int width, - int height, - String mimeType) { - saveFileMediaForUrl(mediaUrl, - fileUrl, - width, - height, - mimeType, - false); - } - - /** - * Copy or Replace a media cache by a file content. - * MediaUrl is the same model as the one used in loadBitmap. - * - * @param mediaUrl the mediaUrl - * @param fileUrl the file which replaces the cached media. - * @param width the expected image width - * @param height the expected image height - * @param mimeType the mimeType. - * @param keepSource keep the source file - */ - public void saveFileMediaForUrl(String mediaUrl, - String fileUrl, - int width, - int height, - String mimeType, - boolean keepSource) { - // We use the download task id to define a cache id - String cacheId = mContentManager.downloadTaskIdForMatrixMediaContent(mediaUrl); - if (null != cacheId) { - if ((width > 0) && (height > 0)) { - cacheId += "_w_" + width + "_h_" + height; - } - String filename = MXMediaDownloadWorkerTask.buildFileName(cacheId, mimeType); - - try { - // delete the current content - File destFile = new File(getFolderFile(mimeType), filename); - - if (destFile.exists()) { - try { - destFile.delete(); - } catch (Exception e) { - Log.e(LOG_TAG, "saveFileMediaForUrl delete failed " + e.getMessage(), e); - } - } - - Uri uri = Uri.parse(fileUrl); - File srcFile = new File(uri.getPath()); - - if (keepSource) { - InputStream in = new FileInputStream(srcFile); - OutputStream out = new FileOutputStream(destFile); - - // Transfer bytes from in to out - byte[] buf = new byte[1024]; - int len; - while ((len = in.read(buf)) > 0) { - out.write(buf, 0, len); - } - in.close(); - out.close(); - } else { - srcFile.renameTo(destFile); - } - - } catch (Exception e) { - Log.e(LOG_TAG, "saveFileMediaForUrl failed " + e.getMessage(), e); - } - } - } - - /** - * Load an avatar thumbnail. - * The imageView image is updated when the bitmap is loaded or downloaded. - * - * @param hsConfig the home server config. - * @param imageView Ihe imageView to update with the image. - * @param url the image url - * @param side the avatar thumbnail side - * @return a download identifier if the image is not cached else null. - */ - public String loadAvatarThumbnail(HomeServerConnectionConfig hsConfig, - ImageView imageView, - String url, - int side) { - return loadBitmap(imageView.getContext(), - hsConfig, - imageView, - url, - side, - side, - 0, - ExifInterface.ORIENTATION_UNDEFINED, - null, - getThumbnailsFolderFile(), - null); - } - - /** - * Load an avatar thumbnail. - * The imageView image is updated when the bitmap is loaded or downloaded. - * - * @param hsConfig the home server config. - * @param imageView Ihe imageView to update with the image. - * @param url the image url - * @param side the avatar thumbnail side - * @param aDefaultAvatar the avatar to use when the Url is not reachable. - * @return a download identifier if the image is not cached else null. - */ - public String loadAvatarThumbnail(HomeServerConnectionConfig hsConfig, - ImageView imageView, - String url, - int side, - Bitmap aDefaultAvatar) { - return loadBitmap(imageView.getContext(), - hsConfig, - imageView, - url, - side, - side, - 0, - ExifInterface.ORIENTATION_UNDEFINED, - null, - getThumbnailsFolderFile(), - aDefaultAvatar, - null); - } - - /** - * Tells if the avatar is cached - * - * @param url the avatar url to test - * @param size the thumbnail size - * @return true if the avatar bitmap is cached. - */ - public boolean isAvatarThumbnailCached(String url, int size) { - boolean isCached = false; - - // We use the download task id to define a cache id - String thumbnailCacheId = mContentManager.downloadTaskIdForMatrixMediaContent(url); - if (null != thumbnailCacheId) { - if (size > 0) { - thumbnailCacheId += "_w_" + size + "_h_" + size; - } - isCached = MXMediaDownloadWorkerTask.isMediaCached(thumbnailCacheId); - - if (!isCached) { - try { - isCached = (new File(getThumbnailsFolderFile(), MXMediaDownloadWorkerTask.buildFileName(thumbnailCacheId, "image/jpeg"))).exists(); - } catch (Throwable t) { - Log.e(LOG_TAG, "## isAvatarThumbnailCached() : failed " + t.getMessage(), t); - } - } - } - - return isCached; - } - - /** - * Tells if the media URL is unreachable. - * - * @param url the url to test. - * @return true if the media URL is unreachable. - */ - public static boolean isMediaUrlUnreachable(String url) { - return MXMediaDownloadWorkerTask.isMediaUrlUnreachable(url); - } - - /** - * Load a bitmap from the url. - * The imageView image is updated when the bitmap is loaded or downloaded. - * - * @param hsConfig The home server config. - * @param imageView The imageView to update with the image. - * @param url the image url - * @param rotationAngle the rotation angle (degrees) - * @param orientation the orientation (ExifInterface.ORIENTATION_XXX value) - * @param mimeType the mimeType. - * @param encryptionInfo the encryption file info - * @return a download identifier if the image is not cached else null. - */ - public String loadBitmap(HomeServerConnectionConfig hsConfig, - ImageView imageView, - String url, - int rotationAngle, - int orientation, - String mimeType, - EncryptedFileInfo encryptionInfo) { - return loadBitmap(hsConfig, - imageView, - url, - -1, - -1, - rotationAngle, - orientation, - mimeType, - encryptionInfo); - } - - /** - * Load a bitmap from the url. - * The imageView image is updated when the bitmap is loaded or downloaded. - * - * @param hsConfig The home server config. - * @param context The context - * @param url the image url - * @param rotationAngle the rotation angle (degrees) - * @param orientation the orientation (ExifInterface.ORIENTATION_XXX value) - * @param mimeType the mimeType. - * @param encryptionInfo the encryption file info - * @return a download identifier if the image is not cached. - */ - public String loadBitmap(Context context, - HomeServerConnectionConfig hsConfig, - String url, - int rotationAngle, - int orientation, - String mimeType, - EncryptedFileInfo encryptionInfo) { - return loadBitmap(context, - hsConfig, - null, - url, - -1, - -1, - rotationAngle, - orientation, - mimeType, - getFolderFile(mimeType), - encryptionInfo); - } - - /** - * Load a bitmap from an url. - * The imageView image is updated when the bitmap is loaded or downloaded. - * The width/height parameters are optional. If they are positive, download a thumbnail. - * rotationAngle is set to Integer.MAX_VALUE when undefined : the EXIF metadata must be checked. - * - * @param hsConfig The home server config. - * @param imageView The imageView to fill when the image is downloaded - * @param url the image url - * @param width the expected image width - * @param height the expected image height - * @param rotationAngle the rotation angle (degrees) - * @param orientation the orientation (ExifInterface.ORIENTATION_XXX value) - * @param mimeType the mimeType. - * @param encryptionInfo the encryption file info - * @return a download identifier if the image is not cached - */ - public String loadBitmap(HomeServerConnectionConfig hsConfig, - ImageView imageView, - String url, - int width, - int height, - int rotationAngle, - int orientation, - String mimeType, - EncryptedFileInfo encryptionInfo) { - return loadBitmap(imageView.getContext(), - hsConfig, - imageView, - url, - width, - height, - rotationAngle, - orientation, - mimeType, - getFolderFile(mimeType), - encryptionInfo); - } - - // some tasks have been stacked because there are too many running ones. - private final List mSuspendedTasks = new ArrayList<>(); - - /** - * Check whether a download is in progress for the content at a Matrix media content URI - * (in the form of "mxc://..."). Returns the identifier of the download task if any. - * - * @param contentUrl the matrix media url - * @return the download ID if there is a pending download or null - */ - @Nullable - public String downloadIdFromUrl(String contentUrl) { - // Check and resolve the provided URL, the resulting URL is used as download identifier. - String downloadId = mContentManager.downloadTaskIdForMatrixMediaContent(contentUrl); - - if (null != downloadId && null != MXMediaDownloadWorkerTask.getMediaDownloadWorkerTask(downloadId)) { - return downloadId; - } - - return null; - } - - /** - * Download a media. - * - * @param context the application context - * @param hsConfig the home server config. - * @param url the media url - * @param mimeType the media mimetype - * @param encryptionInfo the encryption information - * @return the download identifier if there is a pending download else null - */ - public String downloadMedia(Context context, - HomeServerConnectionConfig hsConfig, - String url, - String mimeType, - EncryptedFileInfo encryptionInfo) { - return downloadMedia(context, - hsConfig, - url, - mimeType, - encryptionInfo, - null); - } - - /** - * Download a media. - * - * @param context the application context - * @param hsConfig the home server config. - * @param url the media url - * @param mimeType the media mimetype - * @param encryptionInfo the encryption information - * @param listener the encryption information - * @return the download identifier if there is a pending download else null - */ - public String downloadMedia(Context context, - HomeServerConnectionConfig hsConfig, - String url, - String mimeType, - EncryptedFileInfo encryptionInfo, - IMXMediaDownloadListener listener) { - // sanity checks - if ((null == mimeType) || (null == context)) { - return null; - } - - // Check the provided URL - String downloadId = mContentManager.downloadTaskIdForMatrixMediaContent(url); - - // Return if the media url is not valid, or if the media is already downloaded - if (null == downloadId || isMediaCached(url, mimeType)) { - return null; - } - - // is the media downloading? - MXMediaDownloadWorkerTask task = MXMediaDownloadWorkerTask.getMediaDownloadWorkerTask(downloadId); - if (null != task) { - task.addDownloadListener(listener); - return downloadId; - } - - // Download it in background - String downloadableUrl = mContentManager.getDownloadableUrl(url, null != encryptionInfo); - task = new MXMediaDownloadWorkerTask(context, - hsConfig, - mNetworkConnectivityReceiver, - getFolderFile(mimeType), - downloadableUrl, - downloadId, - 0, - mimeType, - encryptionInfo, - mMediaScanRestClient, - mContentManager.isAvScannerEnabled()); - task.addDownloadListener(listener); - - // avoid crash if there are too many running task - try { - task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } catch (RejectedExecutionException e) { - // too many tasks have been launched - synchronized (mSuspendedTasks) { - task.cancel(true); - // create a new task from the existing one - task = new MXMediaDownloadWorkerTask(task); - mSuspendedTasks.add(task); - // privacy - //Log.e(LOG_TAG, "Suspend the task " + task.getUrl()); - Log.e(LOG_TAG, "Suspend the task ", e); - } - - } catch (Exception e) { - Log.e(LOG_TAG, "downloadMedia failed " + e.getMessage(), e); - synchronized (mSuspendedTasks) { - task.cancel(true); - } - } - - return downloadId; - } - - /** - * Start any suspended task - */ - private void launchSuspendedTask() { - synchronized (mSuspendedTasks) { - // some task have been suspended because there were too many running ones ? - if (!mSuspendedTasks.isEmpty()) { - MXMediaDownloadWorkerTask task = mSuspendedTasks.get(0); - - // privacy - //Log.d(LOG_TAG, "Restart the task " + task.getUrl()); - Log.d(LOG_TAG, "Restart a task "); - - // avoid crash if there are too many running task - try { - task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - mSuspendedTasks.remove(task); - } catch (RejectedExecutionException e) { - task.cancel(true); - - mSuspendedTasks.remove(task); - // create a new task from the existing one - task = new MXMediaDownloadWorkerTask(task); - mSuspendedTasks.add(task); - - // privacy - //Log.d(LOG_TAG, "Suspend again the task " + task.getUrl() + " - " + task.getStatus()); - Log.d(LOG_TAG, "Suspend again the task " + task.getStatus()); - } catch (Exception e) { - Log.e(LOG_TAG, "Try to Restart a task fails " + e.getMessage(), e); - } - } - } - } - - /** - * The default bitmap to use when the media cannot be retrieved. - */ - private static Bitmap mDefaultBitmap = null; - - /** - * Load a bitmap from an url. - * The imageView image is updated when the bitmap is loaded or downloaded. - * The width/height parameters are optional. If they are positive, download a thumbnail. - *

- * The rotation angle is checked first. - * If rotationAngle is set to Integer.MAX_VALUE, check the orientation is defined to a valid value. - * If the orientation is defined, request the properly oriented image to the server - * - * @param context the context - * @param hsConfig the home server config - * @param imageView the imageView to fill when the image is downloaded - * @param url the image url - * @param width the expected image width - * @param height the expected image height - * @param rotationAngle the rotation angle (degrees) - * @param orientation the orientation (ExifInterface.ORIENTATION_XXX value) - * @param mimeType the mimeType. - * @param folderFile the folder where the media should be stored - * @param encryptionInfo the encryption file information. - * @return a download identifier if the image is not cached - */ - public String loadBitmap(Context context, - HomeServerConnectionConfig hsConfig, - final ImageView imageView, - String url, - int width, - int height, - int rotationAngle, - int orientation, - String mimeType, - File folderFile, - EncryptedFileInfo encryptionInfo) { - return loadBitmap(context, - hsConfig, - imageView, - url, - width, - height, - rotationAngle, - orientation, - mimeType, - folderFile, - null, - encryptionInfo); - } - - /** - * Load a bitmap from an url. - * The imageView image is updated when the bitmap is loaded or downloaded. - * The width/height parameters are optional. If they are positive, download a thumbnail. - *

- * The rotation angle is checked first. - * If rotationAngle is set to Integer.MAX_VALUE, check the orientation is defined to a valid value. - * If the orientation is defined, request the properly oriented image to the server - * - * @param context the context - * @param hsConfig the home server config - * @param imageView the imageView to fill when the image is downloaded - * @param url the image url - * @param width the expected image width - * @param height the expected image height - * @param rotationAngle the rotation angle (degrees) - * @param orientation the orientation (ExifInterface.ORIENTATION_XXX value) - * @param mimeType the mimeType. - * @param folderFile the folder where the media should be stored - * @param aDefaultBitmap the default bitmap to use when the url media cannot be retrieved. - * @param encryptionInfo the file encryption info - * @return a download identifier if the image is not cached - */ - public String loadBitmap(Context context, - HomeServerConnectionConfig hsConfig, - final ImageView imageView, - String url, - int width, - int height, - int rotationAngle, - int orientation, - String mimeType, - File folderFile, - Bitmap aDefaultBitmap, - EncryptedFileInfo encryptionInfo) { - // Check invalid bitmap size - if ((0 == width) || (0 == height)) { - return null; - } - - if (null == mDefaultBitmap) { - mDefaultBitmap = BitmapFactory.decodeResource(context.getResources(), android.R.drawable.ic_menu_gallery); - } - - final Bitmap defaultBitmap = (null == aDefaultBitmap) ? mDefaultBitmap : aDefaultBitmap; - - // Check whether the url is valid - String downloadId = mContentManager.downloadTaskIdForMatrixMediaContent(url); - if (null == downloadId) { - // Nothing to do - if (null != imageView) { - imageView.setImageBitmap(defaultBitmap); - } - return null; - } - - // Resolve the provided URL. - // Note: it is not possible to resize an encrypted image. - String downloadableUrl; - if (null == encryptionInfo && width > 0 && height > 0) { - downloadableUrl = mContentManager.getDownloadableThumbnailUrl(url, width, height, ContentManager.METHOD_SCALE); - downloadId += "_w_" + width + "_h_" + height; - } else { - downloadableUrl = mContentManager.getDownloadableUrl(url, null != encryptionInfo); - } - - // the thumbnail params are ignored when encrypted - if ((null == encryptionInfo) - && (rotationAngle == Integer.MAX_VALUE) - && (orientation != ExifInterface.ORIENTATION_UNDEFINED) - && (orientation != ExifInterface.ORIENTATION_NORMAL)) { - if (downloadableUrl.contains("?")) { - downloadableUrl += "&apply_orientation=true"; - } else { - downloadableUrl += "?apply_orientation=true"; - } - downloadId += "_apply_orientation"; - } - - final String fDownloadId = downloadId; - - if (null != imageView) { - imageView.setTag(fDownloadId); - } - - // if the mime type is not provided, assume it is a jpeg file - if (null == mimeType) { - mimeType = "image/jpeg"; - } - - boolean isCached = MXMediaDownloadWorkerTask.bitmapForURL(context.getApplicationContext(), - folderFile, downloadableUrl, downloadId, rotationAngle, mimeType, encryptionInfo, new SimpleApiCallback() { - @Override - public void onSuccess(Bitmap bitmap) { - if (null != imageView) { - if (TextUtils.equals(fDownloadId, (String) imageView.getTag())) { - // display it - imageView.setImageBitmap((null != bitmap) ? bitmap : defaultBitmap); - } - } - } - }); - - if (isCached) { - downloadId = null; - } else { - MXMediaDownloadWorkerTask currentTask = MXMediaDownloadWorkerTask.getMediaDownloadWorkerTask(downloadId); - - if (null != currentTask) { - if (null != imageView) { - currentTask.addImageView(imageView); - } - } else { - // Download it in background - MXMediaDownloadWorkerTask task = new MXMediaDownloadWorkerTask(context, - hsConfig, - mNetworkConnectivityReceiver, - folderFile, - downloadableUrl, - downloadId, - rotationAngle, - mimeType, - encryptionInfo, - mMediaScanRestClient, - mContentManager.isAvScannerEnabled()); - - if (null != imageView) { - task.addImageView(imageView); - } - - task.setDefaultBitmap(defaultBitmap); - - // check at the end of the download, if a suspended task can be launched again. - task.addDownloadListener(new MXMediaDownloadListener() { - @Override - public void onDownloadComplete(String downloadId) { - launchSuspendedTask(); - } - }); - - - // avoid crash if there are too many running task - try { - task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } catch (RejectedExecutionException e) { - // too many tasks have been launched - synchronized (mSuspendedTasks) { - task.cancel(true); - // create a new task from the existing one - task = new MXMediaDownloadWorkerTask(task); - mSuspendedTasks.add(task); - // privacy - //Log.e(LOG_TAG, "Suspend the task " + task.getUrl()); - Log.e(LOG_TAG, "Suspend a task", e); - } - - } catch (Exception e) { - Log.e(LOG_TAG, "loadBitmap failed " + e.getMessage(), e); - } - } - } - - return downloadId; - } - - /** - * Returns the download progress (percentage). - * - * @param downloadId the downloadId provided by loadBitmap; - * @return the download progress - */ - public int getProgressValueForDownloadId(String downloadId) { - MXMediaDownloadWorkerTask currentTask = MXMediaDownloadWorkerTask.getMediaDownloadWorkerTask(downloadId); - - if (null != currentTask) { - return currentTask.getProgress(); - } - return -1; - } - - /** - * Returns the download stats for a dedicated download id. - * - * @param downloadId the downloadId provided by loadBitmap; - * @return the download stats - */ - @Nullable - public IMXMediaDownloadListener.DownloadStats getStatsForDownloadId(String downloadId) { - MXMediaDownloadWorkerTask task = MXMediaDownloadWorkerTask.getMediaDownloadWorkerTask(downloadId); - - if (null != task) { - return task.getDownloadStats(); - } - - return null; - } - - /** - * Add a download listener for an downloadId. - * - * @param downloadId The uploadId. - * @param listener the download listener. - */ - public void addDownloadListener(String downloadId, IMXMediaDownloadListener listener) { - MXMediaDownloadWorkerTask task = MXMediaDownloadWorkerTask.getMediaDownloadWorkerTask(downloadId); - - if (null != task) { - task.addDownloadListener(listener); - } - // Else consider calling listener.onDownloadComplete(downloadId) ? - } - - /** - * Cancel a download. - * - * @param downloadId the download id. - */ - public void cancelDownload(String downloadId) { - MXMediaDownloadWorkerTask task = MXMediaDownloadWorkerTask.getMediaDownloadWorkerTask(downloadId); - - if (null != task) { - task.cancelDownload(); - } - } - - /** - * Upload a file - * - * @param contentStream the stream to upload - * @param filename the dst filename - * @param mimeType the mimetype - * @param uploadId the upload id - * @param listener the upload progress listener - */ - public void uploadContent(InputStream contentStream, - String filename, - String mimeType, - String uploadId, - IMXMediaUploadListener listener) { - try { - new MXMediaUploadWorkerTask(mContentManager, - contentStream, - mimeType, - uploadId, - filename, - listener) - .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } catch (Exception e) { - // cannot start the task - if (null != listener) { - listener.onUploadError(uploadId, -1, null); - } - } - } - - /** - * Returns the upload progress (percentage) for a dedicated uploadId - * - * @param uploadId The uploadId. - * @return the upload percentage. -1 means there is no pending upload. - */ - public int getProgressValueForUploadId(String uploadId) { - MXMediaUploadWorkerTask task = MXMediaUploadWorkerTask.getMediaUploadWorkerTask(uploadId); - - if (null != task) { - return task.getProgress(); - } - - return -1; - } - - /** - * Returns the upload stats for a dedicated uploadId - * - * @param uploadId The uploadId. - * @return the upload stats - */ - public IMXMediaUploadListener.UploadStats getStatsForUploadId(String uploadId) { - MXMediaUploadWorkerTask task = MXMediaUploadWorkerTask.getMediaUploadWorkerTask(uploadId); - - if (null != task) { - return task.getStats(); - } - - return null; - } - - - /** - * Add an upload listener for an uploadId. - * - * @param uploadId The uploadId. - * @param listener the upload listener - */ - public void addUploadListener(String uploadId, IMXMediaUploadListener listener) { - MXMediaUploadWorkerTask task = MXMediaUploadWorkerTask.getMediaUploadWorkerTask(uploadId); - - if (null != task) { - task.addListener(listener); - } - } - - /** - * Cancel an upload. - * - * @param uploadId the upload Id - */ - public void cancelUpload(String uploadId) { - MXMediaUploadWorkerTask task = MXMediaUploadWorkerTask.getMediaUploadWorkerTask(uploadId); - - if (null != task) { - task.cancelUpload(); - } - } - - /** - * Set MediaScan rest client - * - * @param mediaScanRestClient - */ - public void setMediaScanRestClient(MediaScanRestClient mediaScanRestClient) { - mMediaScanRestClient = mediaScanRestClient; - } -} - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/groups/GroupsManager.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/groups/GroupsManager.java deleted file mode 100644 index 4030a3a0..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/groups/GroupsManager.java +++ /dev/null @@ -1,802 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.groups; - -import android.os.Handler; -import android.os.Looper; -import android.support.annotation.NonNull; -import android.text.TextUtils; - -import im.vector.matrix.android.internal.legacy.MXDataHandler; -import im.vector.matrix.android.internal.legacy.MXPatterns; -import im.vector.matrix.android.internal.legacy.data.store.IMXStore; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.SimpleApiCallback; -import im.vector.matrix.android.internal.legacy.rest.client.GroupsRestClient; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.rest.model.RoomMember; -import im.vector.matrix.android.internal.legacy.rest.model.group.CreateGroupParams; -import im.vector.matrix.android.internal.legacy.rest.model.group.Group; -import im.vector.matrix.android.internal.legacy.rest.model.group.GroupProfile; -import im.vector.matrix.android.internal.legacy.rest.model.group.GroupRooms; -import im.vector.matrix.android.internal.legacy.rest.model.group.GroupSummary; -import im.vector.matrix.android.internal.legacy.rest.model.group.GroupSyncProfile; -import im.vector.matrix.android.internal.legacy.rest.model.group.GroupUsers; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * This class manages the groups - */ -public class GroupsManager { - private static final String LOG_TAG = GroupsManager.class.getSimpleName(); - - private MXDataHandler mDataHandler; - private GroupsRestClient mGroupsRestClient; - private IMXStore mStore; - - // callbacks - private Set> mRefreshProfilesCallback = new HashSet<>(); - - // - private final Map> mPendingJoinGroups = new HashMap<>(); - private final Map> mPendingLeaveGroups = new HashMap<>(); - - // publicise management - private Map>>> mPendingPubliciseRequests = new HashMap<>(); - private Map> mPubliciseByUserId = new HashMap<>(); - - private Handler mUIHandler; - - /** - * Constructor - * - * @param dataHandler the data handler - * @param restClient the group rest client - */ - public GroupsManager(MXDataHandler dataHandler, GroupsRestClient restClient) { - mDataHandler = dataHandler; - mStore = mDataHandler.getStore(); - mGroupsRestClient = restClient; - - mUIHandler = new Handler(Looper.getMainLooper()); - } - - /** - * @return the groups rest client - */ - public GroupsRestClient getGroupsRestClient() { - return mGroupsRestClient; - } - - - /** - * Call when the session is paused - */ - public void onSessionPaused() { - mPubliciseByUserId.clear(); - } - - /** - * Call when the session is resumed - */ - public void onSessionResumed() { - refreshGroupProfiles((ApiCallback) null); - getUserPublicisedGroups(mDataHandler.getUserId(), true, new SimpleApiCallback>() { - @Override - public void onSuccess(Set info) { - // Ignore - } - }); - - mGroupProfileByGroupId.clear(); - mGroupProfileCallback.clear(); - } - - /** - * Retrieve the group from a group id - * - * @param groupId the group id - * @return the group if it exists - */ - public Group getGroup(String groupId) { - return mStore.getGroup(groupId); - } - - /** - * @return the existing groups - */ - public Collection getGroups() { - return mStore.getGroups(); - } - - /** - * @return the groups list in which the user is invited - */ - public Collection getInvitedGroups() { - List invitedGroups = new ArrayList<>(); - Collection groups = getGroups(); - - for (Group group : groups) { - if (group.isInvited()) { - invitedGroups.add(group); - } - } - - return invitedGroups; - } - - /** - * @return the joined groups - */ - public Collection getJoinedGroups() { - List joinedGroups = new ArrayList<>(getGroups()); - joinedGroups.removeAll(getInvitedGroups()); - - return joinedGroups; - } - - /** - * Manage the group joining. - * - * @param groupId the group id - * @param notify true to notify - */ - public void onJoinGroup(final String groupId, final boolean notify) { - Group group = getGroup(groupId); - - if (null == group) { - group = new Group(groupId); - } - - if (TextUtils.equals(RoomMember.MEMBERSHIP_JOIN, group.getMembership())) { - Log.d(LOG_TAG, "## onJoinGroup() : the group " + groupId + " was already joined"); - return; - } - - group.setMembership(RoomMember.MEMBERSHIP_JOIN); - mStore.storeGroup(group); - - // try retrieve the summary - mGroupsRestClient.getGroupSummary(groupId, new ApiCallback() { - /** - * Common method - */ - private void onDone() { - if (notify) { - mDataHandler.onJoinGroup(groupId); - } - } - - @Override - public void onSuccess(GroupSummary groupSummary) { - Group group = getGroup(groupId); - - if (null != group) { - group.setGroupSummary(groupSummary); - mStore.flushGroup(group); - onDone(); - - if (null != mPendingJoinGroups.get(groupId)) { - mPendingJoinGroups.get(groupId).onSuccess(null); - mPendingJoinGroups.remove(groupId); - } - } - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "## onJoinGroup() : failed " + e.getMessage(), e); - onDone(); - - if (null != mPendingJoinGroups.get(groupId)) { - mPendingJoinGroups.get(groupId).onNetworkError(e); - mPendingJoinGroups.remove(groupId); - } - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "## onMatrixError() : failed " + e.getMessage()); - onDone(); - - if (null != mPendingJoinGroups.get(groupId)) { - mPendingJoinGroups.get(groupId).onMatrixError(e); - mPendingJoinGroups.remove(groupId); - } - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "## onUnexpectedError() : failed " + e.getMessage(), e); - onDone(); - - if (null != mPendingJoinGroups.get(groupId)) { - mPendingJoinGroups.get(groupId).onUnexpectedError(e); - mPendingJoinGroups.remove(groupId); - } - } - }); - } - - /** - * Create a group from an invitation. - * - * @param groupId the group id - * @param profile the profile - * @param inviter the inviter - * @param notify true to notify - */ - public void onNewGroupInvitation(final String groupId, final GroupSyncProfile profile, final String inviter, final boolean notify) { - Group group = getGroup(groupId); - - // it should always be null - if (null == group) { - group = new Group(groupId); - } - - GroupSummary summary = new GroupSummary(); - summary.profile = new GroupProfile(); - if (null != profile) { - summary.profile.name = profile.name; - summary.profile.avatarUrl = profile.avatarUrl; - } - - group.setGroupSummary(summary); - group.setInviter(inviter); - group.setMembership(RoomMember.MEMBERSHIP_INVITE); - - mStore.storeGroup(group); - - if (notify) { - mUIHandler.post(new Runnable() { - @Override - public void run() { - mDataHandler.onNewGroupInvitation(groupId); - } - }); - } - } - - /** - * Remove a group. - * - * @param groupId the group id. - * @param notify true to notify - */ - public void onLeaveGroup(final String groupId, final boolean notify) { - if (null != mStore.getGroup(groupId)) { - mStore.deleteGroup(groupId); - - mUIHandler.post(new Runnable() { - @Override - public void run() { - if (notify) { - mDataHandler.onLeaveGroup(groupId); - } - - if (mPendingLeaveGroups.containsKey(groupId)) { - mPendingLeaveGroups.get(groupId).onSuccess(null); - mPendingLeaveGroups.remove(groupId); - } - } - }); - } - } - - /** - * Refresh the group profiles - * - * @param callback the asynchronous callback - */ - public void refreshGroupProfiles(ApiCallback callback) { - if (!mRefreshProfilesCallback.isEmpty()) { - Log.d(LOG_TAG, "## refreshGroupProfiles() : there already is a pending request"); - mRefreshProfilesCallback.add(callback); - return; - } - - mRefreshProfilesCallback.add(callback); - refreshGroupProfiles(getGroups().iterator()); - } - - /** - * Internal method to refresh the group profiles. - * - * @param iterator the iterator. - */ - private void refreshGroupProfiles(final Iterator iterator) { - if (!iterator.hasNext()) { - for (ApiCallback callback : mRefreshProfilesCallback) { - try { - if (null != callback) { - callback.onSuccess(null); - } - } catch (Exception e) { - Log.e(LOG_TAG, "## refreshGroupProfiles() failed " + e.getMessage(), e); - } - } - mRefreshProfilesCallback.clear(); - return; - } - - final String groupId = iterator.next().getGroupId(); - - mGroupsRestClient.getGroupProfile(groupId, new ApiCallback() { - private void onDone() { - refreshGroupProfiles(iterator); - } - - @Override - public void onSuccess(GroupProfile profile) { - Group group = getGroup(groupId); - - if (null != group) { - group.setGroupProfile(profile); - mStore.flushGroup(group); - } - - mDataHandler.onGroupProfileUpdate(groupId); - mGroupProfileByGroupId.put(groupId, profile); - onDone(); - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "## refreshGroupProfiles() : failed " + e.getMessage(), e); - onDone(); - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "## refreshGroupProfiles() : failed " + e.getMessage()); - onDone(); - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "## refreshGroupProfiles() : failed " + e.getMessage(), e); - onDone(); - } - }); - } - - /** - * Join a group. - * - * @param groupId the group id - * @param callback the asynchronous callback - */ - public void joinGroup(final String groupId, final ApiCallback callback) { - getGroupsRestClient().joinGroup(groupId, new SimpleApiCallback(callback) { - @Override - public void onSuccess(Void info) { - Group group = getGroup(groupId); - // not yet synced -> wait it is synced - if ((null == group) || TextUtils.equals(group.getMembership(), RoomMember.MEMBERSHIP_INVITE)) { - mPendingJoinGroups.put(groupId, callback); - onJoinGroup(groupId, true); - } else { - callback.onSuccess(null); - } - } - }); - } - - /** - * Leave a group. - * - * @param groupId the group id - * @param callback the asynchronous callback - */ - public void leaveGroup(final String groupId, final ApiCallback callback) { - getGroupsRestClient().leaveGroup(groupId, new SimpleApiCallback(callback) { - @Override - public void onSuccess(Void info) { - Group group = getGroup(groupId); - // not yet synced -> wait it is synced - if (null != group) { - mPendingLeaveGroups.put(groupId, callback); - onLeaveGroup(groupId, true); - } else { - callback.onSuccess(null); - } - } - }); - } - - /** - * Create a group. - * - * @param localPart the local part - * @param groupName the group human name - * @param callback the asynchronous callback - */ - public void createGroup(String localPart, String groupName, final ApiCallback callback) { - final CreateGroupParams params = new CreateGroupParams(); - params.localpart = localPart; - params.profile = new GroupProfile(); - params.profile.name = groupName; - - getGroupsRestClient().createGroup(params, new SimpleApiCallback(callback) { - @Override - public void onSuccess(String groupId) { - Group group = getGroup(groupId); - - // if the group does not exist, create it - if (null == group) { - group = new Group(groupId); - group.setGroupProfile(params.profile); - group.setMembership(RoomMember.MEMBERSHIP_JOIN); - mStore.storeGroup(group); - } - - callback.onSuccess(groupId); - } - }); - } - - /** - * Refresh the group data i.e the invited users list, the users list and the rooms list. - * - * @param group the group - * @param callback the asynchronous callback - */ - public void refreshGroupData(Group group, ApiCallback callback) { - refreshGroupData(group, GROUP_REFRESH_STEP_PROFILE, callback); - } - - private static final int GROUP_REFRESH_STEP_PROFILE = 0; - private static final int GROUP_REFRESH_STEP_ROOMS_LIST = 1; - private static final int GROUP_REFRESH_STEP_USERS_LIST = 2; - private static final int GROUP_REFRESH_STEP_INVITED_USERS_LIST = 3; - - /** - * Internal method to refresh the group informations. - * - * @param group the group - * @param step the current step - * @param callback the asynchronous callback - */ - private void refreshGroupData(final Group group, final int step, final ApiCallback callback) { - if (step == GROUP_REFRESH_STEP_PROFILE) { - getGroupsRestClient().getGroupProfile(group.getGroupId(), new SimpleApiCallback(callback) { - @Override - public void onSuccess(GroupProfile groupProfile) { - group.setGroupProfile(groupProfile); - mStore.flushGroup(group); - mDataHandler.onGroupProfileUpdate(group.getGroupId()); - refreshGroupData(group, GROUP_REFRESH_STEP_ROOMS_LIST, callback); - } - }); - - return; - } - - if (step == GROUP_REFRESH_STEP_ROOMS_LIST) { - getGroupsRestClient().getGroupRooms(group.getGroupId(), new SimpleApiCallback(callback) { - @Override - public void onSuccess(GroupRooms groupRooms) { - group.setGroupRooms(groupRooms); - mStore.flushGroup(group); - mDataHandler.onGroupRoomsListUpdate(group.getGroupId()); - refreshGroupData(group, GROUP_REFRESH_STEP_USERS_LIST, callback); - } - }); - return; - } - - if (step == GROUP_REFRESH_STEP_USERS_LIST) { - getGroupsRestClient().getGroupUsers(group.getGroupId(), new SimpleApiCallback(callback) { - @Override - public void onSuccess(GroupUsers groupUsers) { - group.setGroupUsers(groupUsers); - mStore.flushGroup(group); - mDataHandler.onGroupUsersListUpdate(group.getGroupId()); - refreshGroupData(group, GROUP_REFRESH_STEP_INVITED_USERS_LIST, callback); - } - }); - return; - } - - - //if (step == GROUP_REFRESH_STEP_INVITED_USERS_LIST) - - getGroupsRestClient().getGroupInvitedUsers(group.getGroupId(), new SimpleApiCallback(callback) { - @Override - public void onSuccess(GroupUsers groupUsers) { - group.setInvitedGroupUsers(groupUsers); - - if (null != mStore.getGroup(group.getGroupId())) { - mStore.flushGroup(group); - } - mDataHandler.onGroupInvitedUsersListUpdate(group.getGroupId()); - callback.onSuccess(null); - } - }); - } - - /** - * Retrieves the cached publicisedGroups for an userId. - * - * @param userId the user id - * @return a set if there is a cached one, else null - */ - public Set getUserPublicisedGroups(final String userId) { - if (mPubliciseByUserId.containsKey(userId)) { - return new HashSet<>(mPubliciseByUserId.get(userId)); - } - - return null; - } - - /** - * Request the publicised groups for an user. - * - * @param userId the user id - * @param forceRefresh true to do not use the cached data - * @param callback the asynchronous callback. - */ - public void getUserPublicisedGroups(final String userId, - final boolean forceRefresh, - @NonNull final ApiCallback> callback) { - Log.d(LOG_TAG, "## getUserPublicisedGroups() : " + userId); - - // sanity check - if (!MXPatterns.isUserId(userId)) { - mUIHandler.post(new Runnable() { - @Override - public void run() { - callback.onSuccess(new HashSet()); - } - }); - - return; - } - - // already cached - if (forceRefresh) { - mPubliciseByUserId.remove(userId); - } else { - if (mPubliciseByUserId.containsKey(userId)) { - mUIHandler.post(new Runnable() { - @Override - public void run() { - Log.d(LOG_TAG, "## getUserPublicisedGroups() : " + userId + " --> cached data " + mPubliciseByUserId.get(userId)); - // reported by a rage shake - if (mPubliciseByUserId.containsKey(userId)) { - callback.onSuccess(new HashSet<>(mPubliciseByUserId.get(userId))); - } else { - callback.onSuccess(new HashSet()); - } - } - }); - - return; - } - } - - // request in progress - if (mPendingPubliciseRequests.containsKey(userId)) { - Log.d(LOG_TAG, "## getUserPublicisedGroups() : " + userId + " request in progress"); - mPendingPubliciseRequests.get(userId).add(callback); - return; - } - - mPendingPubliciseRequests.put(userId, new HashSet>>()); - mPendingPubliciseRequests.get(userId).add(callback); - - mGroupsRestClient.getUserPublicisedGroups(userId, new ApiCallback>() { - private void onDone(Set groupIdsSet) { - - // cache only if the request succeeds - // else it will be tried later - if (null != groupIdsSet) { - mPubliciseByUserId.put(userId, new HashSet<>(groupIdsSet)); - } else { - groupIdsSet = new HashSet<>(); - } - - Log.d(LOG_TAG, "## getUserPublicisedGroups() : " + userId + " -- " + groupIdsSet); - - Set>> callbacks = mPendingPubliciseRequests.get(userId); - mPendingPubliciseRequests.remove(userId); - - if (null != callbacks) { - for (ApiCallback> callback : callbacks) { - if (null != callback) { - try { - callback.onSuccess(new HashSet<>(groupIdsSet)); - } catch (Throwable t) { - Log.d(LOG_TAG, "## getUserPublicisedGroups() : callback failed " + t.getMessage()); - } - } - } - } - } - - @Override - public void onSuccess(List groupIdsList) { - onDone((null == groupIdsList) ? new HashSet() : new HashSet<>(groupIdsList)); - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "## getUserPublicisedGroups() : request failed " + e.getMessage(), e); - onDone(null); - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "## getUserPublicisedGroups() : request failed " + e.getMessage()); - onDone(null); - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "## getUserPublicisedGroups() : request failed " + e.getMessage(), e); - onDone(null); - } - }); - } - - /** - * Update a group publicity status. - * - * @param groupId the group id - * @param publicity the new publicity status - * @param callback the asynchronous callback. - */ - public void updateGroupPublicity(final String groupId, final boolean publicity, final ApiCallback callback) { - getGroupsRestClient().updateGroupPublicity(groupId, publicity, new SimpleApiCallback(callback) { - @Override - public void onSuccess(Void info) { - if (mPubliciseByUserId.containsKey(groupId)) { - if (publicity) { - mPubliciseByUserId.get(groupId).add(groupId); - } else { - mPubliciseByUserId.get(groupId).remove(groupId); - } - } - - if (null != callback) { - callback.onSuccess(null); - } - } - }); - } - - Map mGroupProfileByGroupId = new HashMap<>(); - Map>> mGroupProfileCallback = new HashMap<>(); - - - /** - * Retrieve the cached group profile - * - * @param groupId the group id - * @return the cached GroupProfile if it exits, else null - */ - public GroupProfile getGroupProfile(final String groupId) { - return mGroupProfileByGroupId.get(groupId); - } - - /** - * Request the profile of a group. - * - * @param groupId the group id - * @param callback the asynchronous callback - */ - public void getGroupProfile(final String groupId, final ApiCallback callback) { - // sanity check - if (null == callback) { - return; - } - - // valid group id - if (TextUtils.isEmpty(groupId) || !MXPatterns.isGroupId(groupId)) { - mUIHandler.post(new Runnable() { - @Override - public void run() { - callback.onSuccess(new GroupProfile()); - } - }); - - return; - } - - // already downloaded - if (mGroupProfileByGroupId.containsKey(groupId)) { - mUIHandler.post(new Runnable() { - @Override - public void run() { - callback.onSuccess(mGroupProfileByGroupId.get(groupId)); - } - }); - - return; - } - - // in progress - if (mGroupProfileCallback.containsKey(groupId)) { - mGroupProfileCallback.get(groupId).add(callback); - return; - } - - mGroupProfileCallback.put(groupId, new ArrayList<>(Arrays.asList(callback))); - - mGroupsRestClient.getGroupProfile(groupId, new ApiCallback() { - @Override - public void onSuccess(GroupProfile groupProfile) { - mGroupProfileByGroupId.put(groupId, groupProfile); - List> callbacks = mGroupProfileCallback.get(groupId); - mGroupProfileCallback.remove(groupId); - - if (null != callbacks) { - for (ApiCallback c : callbacks) { - c.onSuccess(groupProfile); - } - } - } - - @Override - public void onNetworkError(Exception e) { - List> callbacks = mGroupProfileCallback.get(groupId); - mGroupProfileCallback.remove(groupId); - - if (null != callbacks) { - for (ApiCallback c : callbacks) { - c.onNetworkError(e); - } - } - } - - @Override - public void onMatrixError(MatrixError e) { - List> callbacks = mGroupProfileCallback.get(groupId); - mGroupProfileCallback.remove(groupId); - - if (null != callbacks) { - for (ApiCallback c : callbacks) { - c.onMatrixError(e); - } - } - } - - @Override - public void onUnexpectedError(Exception e) { - List> callbacks = mGroupProfileCallback.get(groupId); - mGroupProfileCallback.remove(groupId); - - if (null != callbacks) { - for (ApiCallback c : callbacks) { - c.onUnexpectedError(e); - } - } - } - }); - - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/interfaces/DatedObject.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/interfaces/DatedObject.java deleted file mode 100644 index 6c43ab44..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/interfaces/DatedObject.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.interfaces; - -/** - * Can be implemented by any object containing a timestamp. - * This interface can be use to sort such object - */ -public interface DatedObject { - long getDate(); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/interfaces/HtmlToolbox.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/interfaces/HtmlToolbox.java deleted file mode 100644 index 0fe4c3a4..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/interfaces/HtmlToolbox.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.interfaces; - -import android.support.annotation.Nullable; -import android.text.Html; - -public interface HtmlToolbox { - - /** - * Convert a html String - * Example: remove not supported html tags, etc. - * - * @param html the source HTML - * @return the converted HTML - */ - String convert(String html); - - /** - * Get a HTML Image Getter - * - * @return a HTML Image Getter or null - */ - @Nullable - Html.ImageGetter getImageGetter(); - - /** - * Get a HTML Tag Handler - * - * @param html the source HTML - * @return a HTML Tag Handler or null - */ - @Nullable - Html.TagHandler getTagHandler(String html); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/IMXEventListener.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/IMXEventListener.java deleted file mode 100644 index 7a4c6f72..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/IMXEventListener.java +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.listeners; - -import im.vector.matrix.android.internal.legacy.data.MyUser; -import im.vector.matrix.android.internal.legacy.data.RoomState; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.rest.model.User; -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.BingRule; - -import java.util.List; - -public interface IMXEventListener { - /** - * The store is ready. - */ - void onStoreReady(); - - /** - * User presence was updated. - * - * @param event The presence event. - * @param user The new user value. - */ - void onPresenceUpdate(Event event, User user); - - /** - * The self user has been updated (display name, avatar url...). - * - * @param myUser The updated myUser - */ - void onAccountInfoUpdate(MyUser myUser); - - /** - * The ignored users list has been updated. - */ - void onIgnoredUsersListUpdate(); - - /** - * The direct chat rooms list have been updated. - */ - void onDirectMessageChatRoomsListUpdate(); - - /** - * A live room event was received. - * - * @param event the event - * @param roomState the room state right before the event - */ - void onLiveEvent(Event event, RoomState roomState); - - /** - * The live events from a chunk are performed. - * - * @param fromToken the start sync token - * @param toToken the up-to sync token - */ - void onLiveEventsChunkProcessed(String fromToken, String toToken); - - /** - * A received event fulfills the bing rules - * The first matched bing rule is provided in paramater to perform - * dedicated action like playing a notification sound. - * - * @param event the event - * @param roomState the room state right before the event - * @param bingRule the bing rule - */ - void onBingEvent(Event event, RoomState roomState, BingRule bingRule); - - /** - * The state of an event has been updated. - * - * @param event the event - */ - void onEventSentStateUpdated(Event event); - - /** - * An event has been sent. - * prevEventId defines the event id set before getting the server new one. - * - * @param event the event - * @param prevEventId the previous eventId - */ - void onEventSent(Event event, String prevEventId); - - /** - * An event has been decrypted - * - * @param event the decrypted event - */ - void onEventDecrypted(Event event); - - /** - * The bing rules have been updated - */ - void onBingRulesUpdate(); - - /** - * The initial sync is complete and the store can be queried for current state. - * - * @param toToken the up-to sync token - */ - void onInitialSyncComplete(String toToken); - - /** - * The sync has encountered an error - * - * @param matrixError the error - */ - void onSyncError(MatrixError matrixError); - - /** - * The crypto sync is complete - */ - void onCryptoSyncComplete(); - - /** - * A new room has been created. - * - * @param roomId the roomID - */ - void onNewRoom(String roomId); - - /** - * The user joined a room. - * - * @param roomId the roomID - */ - void onJoinRoom(String roomId); - - /** - * The messages of an existing room has been flushed during server sync. - * This flush may be due to a limited timeline in the room sync, or the redaction of a state event. - * - * @param roomId the room Id - */ - void onRoomFlush(String roomId); - - /** - * The room data has been internally updated. - * It could be triggered when a request failed. - * - * @param roomId the roomID - */ - void onRoomInternalUpdate(String roomId); - - /** - * The notification count of a dedicated room - * has been updated. - * - * @param roomId the room ID - */ - void onNotificationCountUpdate(String roomId); - - /** - * The user left the room. - * - * @param roomId the roomID - */ - void onLeaveRoom(String roomId); - - /** - * The user has been kicked or banned. - * - * @param roomId the roomID - */ - void onRoomKick(String roomId); - - /** - * A receipt event has been received. - * It could be triggered when a request failed. - * - * @param roomId the roomID - * @param senderIds the list of the - */ - void onReceiptEvent(String roomId, List senderIds); - - /** - * A Room Tag event has been received. - * - * @param roomId the roomID - */ - void onRoomTagEvent(String roomId); - - /** - * A read marker has been updated - * - * @param roomId thr room id. - */ - void onReadMarkerEvent(String roomId); - - /** - * An event was sent to the current device. - * - * @param event the event - */ - void onToDeviceEvent(Event event); - - /** - * The user has been invited to a new group. - * - * @param groupId the group id - */ - void onNewGroupInvitation(String groupId); - - /** - * A group has been joined. - * - * @param groupId the group id - */ - void onJoinGroup(String groupId); - - /** - * A group has been left. - * - * @param groupId the group id - */ - void onLeaveGroup(String groupId); - - /** - * The group file has been updated. - * - * @param groupId the group id - */ - void onGroupProfileUpdate(String groupId); - - /** - * The group rooms list has been updated. - * - * @param groupId the group id - */ - void onGroupRoomsListUpdate(String groupId); - - /** - * The group users id list has been updated. - * - * @param groupId the group id - */ - void onGroupUsersListUpdate(String groupId); - - /** - * The group invited users id list has been updated. - * - * @param groupId the group id - */ - void onGroupInvitedUsersListUpdate(String groupId); -} - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/IMXMediaDownloadListener.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/IMXMediaDownloadListener.java deleted file mode 100644 index 342a9d48..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/IMXMediaDownloadListener.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.listeners; - -import com.google.gson.JsonElement; - -/** - * Interface to monitor a media download. - */ -public interface IMXMediaDownloadListener { - /** - * provide some download stats - */ - class DownloadStats { - /** - * The download id - */ - public String mDownloadId; - - /** - * the download progress in percentage - */ - public int mProgress; - - /** - * The downloaded size in bytes - */ - public int mDownloadedSize; - - /** - * The file size in bytes. - */ - public int mFileSize; - - /** - * time in seconds since the download started - */ - public int mElapsedTime; - - /** - * estimated remained time in seconds to download the media - */ - public int mEstimatedRemainingTime; - - /** - * download bit rate in KB/s - */ - public int mBitRate; - - @Override - public java.lang.String toString() { - String res = ""; - - res += "mProgress : " + mProgress + "%\n"; - res += "mDownloadedSize : " + mDownloadedSize + " bytes\n"; - res += "mFileSize : " + mFileSize + "bytes\n"; - res += "mElapsedTime : " + mProgress + " seconds\n"; - res += "mEstimatedRemainingTime : " + mEstimatedRemainingTime + " seconds\n"; - res += "mBitRate : " + mBitRate + " KB/s\n"; - - return res; - } - } - - /** - * The download starts. - * - * @param downloadId the download Identifier - */ - void onDownloadStart(String downloadId); - - /** - * The download stats have been updated. - * - * @param downloadId the download Identifier - * @param stats the download stats - */ - void onDownloadProgress(String downloadId, DownloadStats stats); - - /** - * The download is completed. - * - * @param downloadId the download Identifier - */ - void onDownloadComplete(String downloadId); - - /** - * The download failed. - * - * @param downloadId the download Identifier - * @param jsonElement the error - */ - void onDownloadError(String downloadId, JsonElement jsonElement); - - /** - * The download has been cancelled. - * - * @param downloadId the download Identifier - */ - void onDownloadCancel(String downloadId); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/IMXMediaUploadListener.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/IMXMediaUploadListener.java deleted file mode 100644 index a89d4b6b..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/IMXMediaUploadListener.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.listeners; - -/** - * Interface to monitor a media upload. - */ -public interface IMXMediaUploadListener { - - /** - * Provide some upload stats - */ - class UploadStats { - /** - * The upload id - */ - public String mUploadId; - - /** - * the upload progress in percentage - */ - public int mProgress; - - /** - * The uploaded size in bytes - */ - public int mUploadedSize; - - /** - * The file size in bytes. - */ - public int mFileSize; - - /** - * time in seconds since the upload started - */ - public int mElapsedTime; - - /** - * estimated remained time in seconds to upload the media - */ - public int mEstimatedRemainingTime; - - /** - * upload bit rate in KB/s - */ - public int mBitRate; - - @Override - public java.lang.String toString() { - String res = ""; - - res += "mProgress : " + mProgress + "%\n"; - res += "mUploadedSize : " + mUploadedSize + " bytes\n"; - res += "mFileSize : " + mFileSize + " bytes\n"; - res += "mElapsedTime : " + mProgress + " seconds\n"; - res += "mEstimatedRemainingTime : " + mEstimatedRemainingTime + " seconds\n"; - res += "mBitRate : " + mBitRate + " KB/s\n"; - - return res; - } - } - - /** - * The upload starts. - * - * @param uploadId the upload Identifier - */ - void onUploadStart(String uploadId); - - /** - * The media upload is in progress. - * - * @param uploadId the upload Identifier - * @param uploadStats the upload stats - */ - void onUploadProgress(String uploadId, UploadStats uploadStats); - - /** - * The upload has been cancelled. - * - * @param uploadId the upload Identifier - */ - void onUploadCancel(String uploadId); - - /** - * The upload fails. - * - * @param uploadId the upload identifier - * @param serverResponseCode the server response code - * @param serverErrorMessage the server error message. - */ - void onUploadError(String uploadId, int serverResponseCode, String serverErrorMessage); - - /** - * The upload failed. - * - * @param uploadId the upload identifier - * @param contentUri the media URI on server. - */ - void onUploadComplete(String uploadId, String contentUri); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/IMXNetworkEventListener.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/IMXNetworkEventListener.java deleted file mode 100644 index 64091b06..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/IMXNetworkEventListener.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2015 OpenMarket 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.matrix.android.internal.legacy.listeners; - - -public interface IMXNetworkEventListener { - /** - * The network connection has been updated - * - * @param isConnected true if the device uses a data connection. - */ - void onNetworkConnectionUpdate(boolean isConnected); -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/MXEventListener.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/MXEventListener.java deleted file mode 100644 index 39bff6e9..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/MXEventListener.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.listeners; - -import im.vector.matrix.android.internal.legacy.data.MyUser; -import im.vector.matrix.android.internal.legacy.data.RoomState; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.rest.model.User; -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.BingRule; - -import java.util.List; - -/** - * A no-op class implementing {@link IMXEventListener} so listeners can just implement the methods - * that they require. - */ -public class MXEventListener implements IMXEventListener { - - @Override - public void onStoreReady() { - } - - @Override - public void onPresenceUpdate(Event event, User user) { - } - - @Override - public void onAccountInfoUpdate(MyUser myUser) { - } - - @Override - public void onLiveEvent(Event event, RoomState roomState) { - - } - - @Override - public void onLiveEventsChunkProcessed(String fromToken, String toToken) { - } - - @Override - public void onBingEvent(Event event, RoomState roomState, BingRule bingRule) { - } - - @Override - public void onEventSent(final Event event, final String prevEventId) { - } - - @Override - public void onEventSentStateUpdated(Event event) { - } - - @Override - public void onEventDecrypted(Event event) { - } - - @Override - public void onBingRulesUpdate() { - } - - @Override - public void onInitialSyncComplete(String toToken) { - } - - @Override - public void onSyncError(MatrixError matrixError) { - } - - @Override - public void onCryptoSyncComplete() { - } - - @Override - public void onNewRoom(String roomId) { - } - - @Override - public void onJoinRoom(String roomId) { - } - - @Override - public void onRoomInternalUpdate(String roomId) { - } - - @Override - public void onNotificationCountUpdate(String roomId) { - } - - @Override - public void onLeaveRoom(String roomId) { - } - - @Override - public void onRoomKick(String roomId) { - } - - @Override - public void onReceiptEvent(String roomId, List senderIds) { - } - - @Override - public void onRoomTagEvent(String roomId) { - } - - @Override - public void onReadMarkerEvent(String roomId) { - } - - @Override - public void onRoomFlush(String roomId) { - } - - @Override - public void onIgnoredUsersListUpdate() { - } - - @Override - public void onToDeviceEvent(Event event) { - } - - @Override - public void onDirectMessageChatRoomsListUpdate() { - } - - @Override - public void onNewGroupInvitation(String groupId) { - } - - @Override - public void onJoinGroup(String groupId) { - } - - @Override - public void onLeaveGroup(String groupId) { - } - - @Override - public void onGroupProfileUpdate(String groupId) { - } - - @Override - public void onGroupRoomsListUpdate(String groupId) { - } - - @Override - public void onGroupUsersListUpdate(String groupId) { - } - - @Override - public void onGroupInvitedUsersListUpdate(String groupId) { - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/MXMediaDownloadListener.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/MXMediaDownloadListener.java deleted file mode 100644 index 05a66dfb..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/MXMediaDownloadListener.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.listeners; - -import com.google.gson.JsonElement; - -/** - * A no-op class implementing {@link IMXMediaDownloadListener} so listeners can just implement the methods - * that they require. - */ -public class MXMediaDownloadListener implements IMXMediaDownloadListener { - - @Override - public void onDownloadStart(String downloadId) { - } - - @Override - public void onDownloadProgress(String downloadId, DownloadStats stats) { - } - - @Override - public void onDownloadComplete(String downloadId) { - } - - @Override - public void onDownloadError(String downloadId, JsonElement jsonElement) { - } - - @Override - public void onDownloadCancel(String downloadId) { - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/MXMediaUploadListener.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/MXMediaUploadListener.java deleted file mode 100644 index 5c771b18..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/MXMediaUploadListener.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.listeners; - -/** - * A no-op class implementing {@link IMXMediaUploadListener} so listeners can just implement the methods - * that they require. - */ -public class MXMediaUploadListener implements IMXMediaUploadListener { - @Override - public void onUploadStart(String uploadId) { - } - - @Override - public void onUploadProgress(String uploadId, UploadStats uploadStats) { - } - - @Override - public void onUploadCancel(String uploadId) { - } - - @Override - public void onUploadError(String uploadId, int serverResponseCode, String serverErrorMessage) { - } - - @Override - public void onUploadComplete(String uploadId, String contentUri) { - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/MXRoomEventListener.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/MXRoomEventListener.java deleted file mode 100644 index ffcf8b91..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/listeners/MXRoomEventListener.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.listeners; - -import android.support.annotation.NonNull; -import android.text.TextUtils; - -import im.vector.matrix.android.internal.legacy.data.Room; -import im.vector.matrix.android.internal.legacy.data.RoomState; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.User; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.util.List; - -/** - * A listener which filter event for a specific room - */ -public class MXRoomEventListener extends MXEventListener { - - private static final String LOG_TAG = MXRoomEventListener.class.getSimpleName(); - - private final String mRoomId; - private final IMXEventListener mEventListener; - private final Room mRoom; - - public MXRoomEventListener(@NonNull Room room, - @NonNull IMXEventListener eventListener) { - mRoom = room; - mRoomId = room.getRoomId(); - mEventListener = eventListener; - } - - @Override - public void onPresenceUpdate(Event event, User user) { - // Only pass event through if the user is a member of the room - // FIXME LazyLoading. We cannot rely on getMember nullity anymore - if (mRoom.getMember(user.user_id) != null) { - try { - mEventListener.onPresenceUpdate(event, user); - } catch (Exception e) { - Log.e(LOG_TAG, "onPresenceUpdate exception " + e.getMessage(), e); - } - } - } - - @Override - public void onLiveEvent(Event event, RoomState roomState) { - // Filter out events for other rooms and events while we are joining (before the room is ready) - if (TextUtils.equals(mRoomId, event.roomId) && mRoom.isReady()) { - try { - mEventListener.onLiveEvent(event, roomState); - } catch (Exception e) { - Log.e(LOG_TAG, "onLiveEvent exception " + e.getMessage(), e); - } - } - } - - @Override - public void onLiveEventsChunkProcessed(String fromToken, String toToken) { - try { - mEventListener.onLiveEventsChunkProcessed(fromToken, toToken); - } catch (Exception e) { - Log.e(LOG_TAG, "onLiveEventsChunkProcessed exception " + e.getMessage(), e); - } - } - - @Override - public void onEventSentStateUpdated(Event event) { - // Filter out events for other rooms - if (TextUtils.equals(mRoomId, event.roomId)) { - try { - mEventListener.onEventSentStateUpdated(event); - } catch (Exception e) { - Log.e(LOG_TAG, "onEventSentStateUpdated exception " + e.getMessage(), e); - } - } - } - - @Override - public void onEventDecrypted(Event event) { - // Filter out events for other rooms - if (TextUtils.equals(mRoomId, event.roomId)) { - try { - mEventListener.onEventDecrypted(event); - } catch (Exception e) { - Log.e(LOG_TAG, "onDecryptedEvent exception " + e.getMessage(), e); - } - } - } - - @Override - public void onEventSent(final Event event, final String prevEventId) { - // Filter out events for other rooms - if (TextUtils.equals(mRoomId, event.roomId)) { - try { - mEventListener.onEventSent(event, prevEventId); - } catch (Exception e) { - Log.e(LOG_TAG, "onEventSent exception " + e.getMessage(), e); - } - } - } - - @Override - public void onRoomInternalUpdate(String roomId) { - // Filter out events for other rooms - if (TextUtils.equals(mRoomId, roomId)) { - try { - mEventListener.onRoomInternalUpdate(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onRoomInternalUpdate exception " + e.getMessage(), e); - } - } - } - - @Override - public void onNotificationCountUpdate(String roomId) { - // Filter out events for other rooms - if (TextUtils.equals(mRoomId, roomId)) { - try { - mEventListener.onNotificationCountUpdate(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onNotificationCountUpdate exception " + e.getMessage(), e); - } - } - } - - @Override - public void onNewRoom(String roomId) { - // Filter out events for other rooms - if (TextUtils.equals(mRoomId, roomId)) { - try { - mEventListener.onNewRoom(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onNewRoom exception " + e.getMessage(), e); - } - } - } - - @Override - public void onJoinRoom(String roomId) { - // Filter out events for other rooms - if (TextUtils.equals(mRoomId, roomId)) { - try { - mEventListener.onJoinRoom(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onJoinRoom exception " + e.getMessage(), e); - } - } - } - - @Override - public void onReceiptEvent(String roomId, List senderIds) { - // Filter out events for other rooms - if (TextUtils.equals(mRoomId, roomId)) { - try { - mEventListener.onReceiptEvent(roomId, senderIds); - } catch (Exception e) { - Log.e(LOG_TAG, "onReceiptEvent exception " + e.getMessage(), e); - } - } - } - - @Override - public void onRoomTagEvent(String roomId) { - // Filter out events for other rooms - if (TextUtils.equals(mRoomId, roomId)) { - try { - mEventListener.onRoomTagEvent(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onRoomTagEvent exception " + e.getMessage(), e); - } - } - } - - @Override - public void onReadMarkerEvent(String roomId) { - // Filter out events for other rooms - if (TextUtils.equals(mRoomId, roomId)) { - try { - mEventListener.onReadMarkerEvent(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onReadMarkerEvent exception " + e.getMessage(), e); - } - } - } - - @Override - public void onRoomFlush(String roomId) { - // Filter out events for other rooms - if (TextUtils.equals(mRoomId, roomId)) { - try { - mEventListener.onRoomFlush(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onRoomFlush exception " + e.getMessage(), e); - } - } - } - - @Override - public void onLeaveRoom(String roomId) { - // Filter out events for other rooms - if (TextUtils.equals(mRoomId, roomId)) { - try { - mEventListener.onLeaveRoom(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onLeaveRoom exception " + e.getMessage(), e); - } - } - } - - @Override - public void onRoomKick(String roomId) { - // Filter out events for other rooms - if (TextUtils.equals(mRoomId, roomId)) { - try { - mEventListener.onRoomKick(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onRoomKick exception " + e.getMessage(), e); - } - } - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/network/NetworkConnectivityReceiver.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/network/NetworkConnectivityReceiver.java deleted file mode 100644 index 4e24097b..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/network/NetworkConnectivityReceiver.java +++ /dev/null @@ -1,317 +0,0 @@ -/* - * Copyright 2015 OpenMarket 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.matrix.android.internal.legacy.network; - -import android.annotation.SuppressLint; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.net.ConnectivityManager; -import android.net.Network; -import android.net.NetworkInfo; -import android.os.Build; -import android.os.Bundle; -import android.telephony.TelephonyManager; - -import im.vector.matrix.android.internal.legacy.util.Log; - -import im.vector.matrix.android.internal.legacy.listeners.IMXNetworkEventListener; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Set; - -public class NetworkConnectivityReceiver extends BroadcastReceiver { - - private static final String LOG_TAG = NetworkConnectivityReceiver.class.getSimpleName(); - - // any network state listener - private final List mNetworkEventListeners = new ArrayList<>(); - - // the one call listeners are listeners which are expected to be called ONCE - // the device is connected to a data network - private final List mOnNetworkConnectedEventListeners = new ArrayList<>(); - - private boolean mIsConnected = false; - private boolean mIsUseWifiConnection = false; - private int mNetworkSubType = TelephonyManager.NETWORK_TYPE_UNKNOWN; - - @Override - public void onReceive(final Context context, final Intent intent) { - NetworkInfo networkInfo = null; - - if (null != intent) { - - Log.d(LOG_TAG, "## onReceive() : action " + intent.getAction()); - - Bundle extras = intent.getExtras(); - - if (null != extras) { - Set keys = extras.keySet(); - - for (String key : keys) { - Log.d(LOG_TAG, "## onReceive() : " + key + " -> " + extras.get(key)); - } - - if (extras.containsKey("networkInfo")) { - Object networkInfoAsVoid = extras.get("networkInfo"); - - if (networkInfoAsVoid instanceof NetworkInfo) { - networkInfo = (NetworkInfo) networkInfoAsVoid; - } - } - } - } else { - Log.d(LOG_TAG, "## onReceive()"); - } - - checkNetworkConnection(context, networkInfo); - } - - /** - * Check if there is a connection update. - * - * @param context the context - */ - public void checkNetworkConnection(Context context) { - checkNetworkConnection(context, null); - } - - /** - * Check if there is a connection update. - * - * @param context the context - */ - private void checkNetworkConnection(Context context, NetworkInfo aNetworkInfo) { - synchronized (LOG_TAG) { - try { - NetworkInfo networkInfo = aNetworkInfo; - - // https://issuetracker.google.com/issues/37137911 - // it seems that getActiveNetworkInfo does not provide the true active network connection - if (null == networkInfo) { - ConnectivityManager connMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - networkInfo = connMgr.getActiveNetworkInfo(); - } - boolean isConnected = (networkInfo != null) && networkInfo.isConnectedOrConnecting(); - - if (isConnected) { - Log.d(LOG_TAG, "## checkNetworkConnection() : Connected to " + networkInfo); - } else if (null != networkInfo) { - Log.d(LOG_TAG, "## checkNetworkConnection() : there is a default connection but it is not connected " + networkInfo); - listNetworkConnections(context); - } else { - Log.d(LOG_TAG, "## checkNetworkConnection() : there is no connection"); - listNetworkConnections(context); - } - - mIsUseWifiConnection = (null != networkInfo) && (networkInfo.getType() == ConnectivityManager.TYPE_WIFI); - mNetworkSubType = (null != networkInfo) ? networkInfo.getSubtype() : TelephonyManager.NETWORK_TYPE_UNKNOWN; - - // avoid triggering useless info - if (mIsConnected != isConnected) { - Log.d(LOG_TAG, "## checkNetworkConnection() : Warn there is a connection update"); - mIsConnected = isConnected; - onNetworkUpdate(); - } else { - Log.d(LOG_TAG, "## checkNetworkConnection() : No network update"); - } - } catch (Exception e) { - Log.e(LOG_TAG, "Failed to report :" + e.getMessage(), e); - } - } - } - - /** - * List the available network connections - * - * @param context the context - */ - @SuppressLint("deprecation") - private static void listNetworkConnections(Context context) { - ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - List networkInfos = new ArrayList<>(); - - // - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - Network[] activeNetworks = cm.getAllNetworks(); - if (null != activeNetworks) { - for (Network network : activeNetworks) { - NetworkInfo networkInfo = cm.getNetworkInfo(network); - if (null != networkInfo) { - networkInfos.add(networkInfo); - } - } - } - } else { - NetworkInfo[] info = cm.getAllNetworkInfo(); - - if (info != null) { - networkInfos.addAll(Arrays.asList(info)); - } - } - - Log.d(LOG_TAG, "## listNetworkConnections() : " + networkInfos.size() + " connections"); - - for (NetworkInfo networkInfo : networkInfos) { - Log.d(LOG_TAG, "-> " + networkInfo); - } - } - - /** - * Add a network event listener. - * - * @param networkEventListener the event listener to add - */ - public void addEventListener(final IMXNetworkEventListener networkEventListener) { - if (null != networkEventListener) { - mNetworkEventListeners.add(networkEventListener); - } - } - - /** - * Add a ONE CALL network event listener. - * The listener is called when a data connection is established. - * The listener is removed from the listeners list once its callback is called. - * - * @param networkEventListener the event listener to add - */ - public void addOnConnectedEventListener(final IMXNetworkEventListener networkEventListener) { - if (null != networkEventListener) { - synchronized (LOG_TAG) { - mOnNetworkConnectedEventListeners.add(networkEventListener); - } - } - } - - /** - * Remove a network event listener. - * - * @param networkEventListener the event listener to remove - */ - public void removeEventListener(final IMXNetworkEventListener networkEventListener) { - synchronized (LOG_TAG) { - mNetworkEventListeners.remove(networkEventListener); - mOnNetworkConnectedEventListeners.remove(networkEventListener); - } - } - - /** - * Remove all registered listeners - */ - public void removeListeners() { - synchronized (LOG_TAG) { - mNetworkEventListeners.clear(); - mOnNetworkConnectedEventListeners.clear(); - } - } - - /** - * Warn the listener that a network updated has been triggered - */ - private synchronized void onNetworkUpdate() { - for (IMXNetworkEventListener listener : mNetworkEventListeners) { - try { - listener.onNetworkConnectionUpdate(mIsConnected); - } catch (Exception e) { - Log.e(LOG_TAG, "## onNetworkUpdate() : onNetworkConnectionUpdate failed " + e.getMessage(), e); - } - } - - // onConnected listeners are called once - // and only when there is an available network connection - if (mIsConnected) { - for (IMXNetworkEventListener listener : mOnNetworkConnectedEventListeners) { - try { - listener.onNetworkConnectionUpdate(true); - } catch (Exception e) { - Log.e(LOG_TAG, "## onNetworkUpdate() : onNetworkConnectionUpdate failed " + e.getMessage(), e); - } - } - - mOnNetworkConnectedEventListeners.clear(); - } - } - - /** - * @return true if the application is connected to a data network - */ - public boolean isConnected() { - boolean res; - - synchronized (LOG_TAG) { - res = mIsConnected; - } - - Log.d(LOG_TAG, "## isConnected() : " + res); - - return res; - } - - - /** - * Tells if the connection is a wifi one - * - * @return true if a wifi connection is used - */ - public boolean useWifiConnection() { - boolean res; - - synchronized (LOG_TAG) { - res = mIsUseWifiConnection; - } - - Log.d(LOG_TAG, "## useWifiConnection() : " + res); - - return res; - } - - /** - * Provides a scale factor to apply to the request timeouts. - * - * @return the scale factor - */ - public float getTimeoutScale() { - float scale; - - synchronized (LOG_TAG) { - switch (mNetworkSubType) { - case TelephonyManager.NETWORK_TYPE_GPRS: - scale = 3.0f; - break; - case TelephonyManager.NETWORK_TYPE_EDGE: - scale = 2.5f; - break; - case TelephonyManager.NETWORK_TYPE_UMTS: - case TelephonyManager.NETWORK_TYPE_CDMA: - case TelephonyManager.NETWORK_TYPE_HSPA: - case TelephonyManager.NETWORK_TYPE_HSDPA: - case TelephonyManager.NETWORK_TYPE_HSUPA: - case TelephonyManager.NETWORK_TYPE_HSPAP: - scale = 2.0f; - break; - case TelephonyManager.NETWORK_TYPE_LTE: - scale = 1.5f; - break; - default: - scale = 1.0f; - break; - } - } - return scale; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/AccountDataApi.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/AccountDataApi.java deleted file mode 100644 index b25af37e..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/AccountDataApi.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2015 OpenMarket 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.matrix.android.internal.legacy.rest.api; - -import java.util.Map; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.POST; -import retrofit2.http.PUT; -import retrofit2.http.Path; - -public interface AccountDataApi { - - /** - * Set some account_data for the client. - * - * @param userId the user id - * @param type the type - * @param params the put params - */ - @PUT("user/{userId}/account_data/{type}") - Call setAccountData(@Path("userId") String userId, @Path("type") String type, @Body Object params); - - /** - * Gets a bearer token from the homeserver that the user can - * present to a third party in order to prove their ownership - * of the Matrix account they are logged into. - * - * @param userId the user id - * @param body the body content - */ - @POST("user/{userId}/openid/request_token") - Call> openIdToken(@Path("userId") String userId, @Body Map body); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/CallRulesApi.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/CallRulesApi.java deleted file mode 100644 index 6c5a8069..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/CallRulesApi.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2015 OpenMarket 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.matrix.android.internal.legacy.rest.api; - -import com.google.gson.JsonObject; - -import retrofit2.Call; -import retrofit2.http.GET; - -public interface CallRulesApi { - @GET("voip/turnServer") - Call getTurnServer(); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/CryptoApi.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/CryptoApi.java deleted file mode 100644 index 58e37e62..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/CryptoApi.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.rest.api; - - -import im.vector.matrix.android.internal.legacy.rest.model.pid.DeleteDeviceParams; -import im.vector.matrix.android.internal.legacy.rest.model.sync.DevicesListResponse; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.KeyChangesResponse; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.KeysClaimResponse; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.KeysQueryResponse; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.KeysUploadResponse; - -import java.util.Map; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.GET; -import retrofit2.http.HTTP; -import retrofit2.http.POST; -import retrofit2.http.PUT; -import retrofit2.http.Path; -import retrofit2.http.Query; - -public interface CryptoApi { - - /** - * Upload device and/or one-time keys. - * @param params the params. - */ - @POST("keys/upload") - Call uploadKeys(@Body Map params); - - /** - * Upload device and/or one-time keys. - * - * @param deviceId the deviceId - * @param params the params. - */ - @POST("keys/upload/{deviceId}") - Call uploadKeys(@Path("deviceId") String deviceId, @Body Map params); - - /** - * Download device keys. - * @param params the params. - */ - @POST("keys/query") - Call downloadKeysForUsers(@Body Map params); - - /** - * Claim one-time keys. - * @param params the params. - */ - @POST("keys/claim") - Call claimOneTimeKeysForUsersDevices(@Body Map params); - - /** - * Send an event to a specific list of devices - * - * @param eventType the type of event to send - * @param transactionId the random path item - * @param params the params - */ - @PUT("sendToDevice/{eventType}/{random}") - Call sendToDevice(@Path("eventType") String eventType, @Path("random") String transactionId, @Body Map params); - - /** - * Get the devices list - */ - @GET("devices") - Call getDevices(); - - /** - * Delete a device. - * - * @param deviceId the device id - * @param params the deletion parameters - */ - @HTTP(path = "devices/{device_id}", method = "DELETE", hasBody = true) - Call deleteDevice(@Path("device_id") String deviceId, @Body DeleteDeviceParams params); - - /** - * Update the device information. - * - * @param deviceId the device id - * @param params the params - */ - @PUT("devices/{device_id}") - Call updateDeviceInfo(@Path("device_id") String deviceId, @Body Map params); - - /** - * Get the update devices list from two sync token. - * - * @param oldToken the start token. - * @param newToken the up-to token. - */ - @GET("keys/changes") - Call getKeyChanges(@Query("from") String oldToken, @Query("to") String newToken); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/EventsApi.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/EventsApi.java deleted file mode 100644 index 414616fa..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/EventsApi.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.rest.api; - -import im.vector.matrix.android.internal.legacy.RestClient; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.pid.ThirdPartyProtocol; -import im.vector.matrix.android.internal.legacy.rest.model.publicroom.PublicRoomsParams; -import im.vector.matrix.android.internal.legacy.rest.model.publicroom.PublicRoomsResponse; -import im.vector.matrix.android.internal.legacy.rest.model.search.SearchParams; -import im.vector.matrix.android.internal.legacy.rest.model.search.SearchResponse; -import im.vector.matrix.android.internal.legacy.rest.model.search.SearchUsersParams; -import im.vector.matrix.android.internal.legacy.rest.model.search.SearchUsersRequestResponse; -import im.vector.matrix.android.internal.legacy.rest.model.sync.SyncResponse; - -import java.util.Map; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.GET; -import retrofit2.http.POST; -import retrofit2.http.Path; -import retrofit2.http.Query; -import retrofit2.http.QueryMap; - -/** - * The events API. - */ -public interface EventsApi { - - /** - * Perform the initial sync to find the rooms that concern the user, the participants' presence, etc. - * - * @param params the GET params. - */ - @GET(RestClient.URI_API_PREFIX_PATH_R0 + "sync") - Call sync(@QueryMap Map params); - - /** - * Retrieve an event from its event id - * - * @param eventId the event Id - */ - @GET(RestClient.URI_API_PREFIX_PATH_R0 + "events/{eventId}") - Call getEvent(@Path("eventId") String eventId); - - /** - * Get the third party server protocols. - */ - @GET(RestClient.URI_API_PREFIX_PATH_UNSTABLE + "thirdparty/protocols") - Call> thirdPartyProtocols(); - - /** - * Get the list of public rooms. - * - * @param server the server (might be null) - * @param publicRoomsParams the request params - */ - @POST(RestClient.URI_API_PREFIX_PATH_R0 + "publicRooms") - Call publicRooms(@Query("server") String server, @Body PublicRoomsParams publicRoomsParams); - - /** - * Perform a search. - * - * @param searchParams the search params. - * @param nextBatch the next batch token - */ - @POST(RestClient.URI_API_PREFIX_PATH_R0 + "search") - Call searchEvents(@Body SearchParams searchParams, @Query("next_batch") String nextBatch); - - /** - * Perform an users search. - * - * @param searchUsersParams the search params. - */ - @POST(RestClient.URI_API_PREFIX_PATH_R0 + "user_directory/search") - Call searchUsers(@Body SearchUsersParams searchUsersParams); - - /** - * Retrieve the preview information of an URL. - * - * @param url the URL - * @param ts the ts - */ - @GET(RestClient.URI_API_PREFIX_PATH_MEDIA_R0 + "preview_url") - Call> getURLPreview(@Query("url") String url, @Query("ts") long ts); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/FilterApi.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/FilterApi.java deleted file mode 100644 index 4acade8d..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/FilterApi.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2018 Matthias Kesler - * Copyright 2018 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.matrix.android.internal.legacy.rest.api; - -import im.vector.matrix.android.internal.legacy.rest.model.filter.FilterBody; -import im.vector.matrix.android.internal.legacy.rest.model.filter.FilterResponse; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.GET; -import retrofit2.http.POST; -import retrofit2.http.Path; - -public interface FilterApi { - - /** - * Upload FilterBody to get a filter_id which can be used for /sync requests - * - * @param userId the user id - * @param body the Json representation of a FilterBody object - */ - @POST("user/{userId}/filter") - Call uploadFilter(@Path("userId") String userId, @Body FilterBody body); - - /** - * Gets a filter with a given filterId from the homeserver - * - * @param userId the user id - * @param filterId the filterID - * @return Filter - */ - @GET("user/{userId}/filter/{filterId}") - Call getFilterById(@Path("userId") String userId, @Path("filterId") String filterId); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/GroupsApi.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/GroupsApi.java deleted file mode 100644 index bfde2f68..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/GroupsApi.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.rest.api; - -import im.vector.matrix.android.internal.legacy.rest.model.group.AcceptGroupInvitationParams; -import im.vector.matrix.android.internal.legacy.rest.model.group.AddGroupParams; -import im.vector.matrix.android.internal.legacy.rest.model.group.CreateGroupParams; -import im.vector.matrix.android.internal.legacy.rest.model.group.CreateGroupResponse; -import im.vector.matrix.android.internal.legacy.rest.model.group.GetGroupsResponse; -import im.vector.matrix.android.internal.legacy.rest.model.group.GetPublicisedGroupsResponse; -import im.vector.matrix.android.internal.legacy.rest.model.group.GroupInviteUserParams; -import im.vector.matrix.android.internal.legacy.rest.model.group.GroupInviteUserResponse; -import im.vector.matrix.android.internal.legacy.rest.model.group.GroupKickUserParams; -import im.vector.matrix.android.internal.legacy.rest.model.group.GroupProfile; -import im.vector.matrix.android.internal.legacy.rest.model.group.GroupRooms; -import im.vector.matrix.android.internal.legacy.rest.model.group.GroupSummary; -import im.vector.matrix.android.internal.legacy.rest.model.group.GroupUsers; -import im.vector.matrix.android.internal.legacy.rest.model.group.LeaveGroupParams; -import im.vector.matrix.android.internal.legacy.rest.model.group.UpdatePubliciseParams; - -import java.util.List; -import java.util.Map; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.DELETE; -import retrofit2.http.GET; -import retrofit2.http.POST; -import retrofit2.http.PUT; -import retrofit2.http.Path; - -/** - * The groups API. - */ -public interface GroupsApi { - - /** - * Create a group - * - * @param params the group creation params - */ - @POST("create_group") - Call createGroup(@Body CreateGroupParams params); - - /** - * Invite an user to a group. - * - * @param groupId the group id - * @param userId the user id - * @param params the invitation parameters - */ - @PUT("groups/{groupId}/admin/users/invite/{userId}") - Call inviteUser(@Path("groupId") String groupId, @Path("userId") String userId, @Body GroupInviteUserParams params); - - /** - * Kick an user from a group. - * - * @param groupId the group id - * @param userId the user id - * @param params the kick parameters - */ - @PUT("groups/{groupId}/users/remove/{userId}") - Call kickUser(@Path("groupId") String groupId, @Path("userId") String userId, @Body GroupKickUserParams params); - - /** - * Add a room in a group. - * - * @param groupId the group id - * @param roomId the room id - * @param params the kick parameters - */ - @PUT("groups/{groupId}/admin/rooms/{roomId}") - Call addRoom(@Path("groupId") String groupId, @Path("roomId") String roomId, @Body AddGroupParams params); - - /** - * Remove a room from a group. - * - * @param groupId the group id - * @param roomId the room id - */ - @DELETE("groups/{groupId}/admin/rooms/{roomId}") - Call removeRoom(@Path("groupId") String groupId, @Path("roomId") String roomId); - - /** - * Update the group profile. - * - * @param groupId the group id - * @param profile the group profile - */ - @POST("groups/{groupId}/profile") - Call updateProfile(@Path("groupId") String groupId, @Body GroupProfile profile); - - /** - * Get the group profile. - * - * @param groupId the group id - */ - @GET("groups/{groupId}/profile") - Call getProfile(@Path("groupId") String groupId); - - /** - * Request the invited users list. - * - * @param groupId the group id - */ - @GET("groups/{groupId}/invited_users") - Call getInvitedUsers(@Path("groupId") String groupId); - - /** - * Request the users list. - * - * @param groupId the group id - */ - @GET("groups/{groupId}/users") - Call getUsers(@Path("groupId") String groupId); - - /** - * Request the rooms list. - * - * @param groupId the group id - */ - @GET("groups/{groupId}/rooms") - Call getRooms(@Path("groupId") String groupId); - - /** - * Request a group summary - * - * @param groupId the group id - */ - @GET("groups/{groupId}/summary") - Call getSummary(@Path("groupId") String groupId); - - /** - * Accept an invitation in a group. - * - * @param groupId the group id - * @param params the parameters - */ - @PUT("groups/{groupId}/self/accept_invite") - Call acceptInvitation(@Path("groupId") String groupId, @Body AcceptGroupInvitationParams params); - - /** - * Leave a group - * - * @param groupId the group id - * @param params the parameters - */ - @PUT("groups/{groupId}/self/leave") - Call leave(@Path("groupId") String groupId, @Body LeaveGroupParams params); - - /** - * Update the publicity status. - * - * @param groupId the group id - * @param params the parameters - */ - @PUT("groups/{groupId}/self/update_publicity") - Call updatePublicity(@Path("groupId") String groupId, @Body UpdatePubliciseParams params); - - /** - * Request the joined group list. - */ - @GET("joined_groups") - Call getJoinedGroupIds(); - - // NOT FEDERATED - /** - * Request the publicised groups for an user id. - * - * @param userId the user id - */ - //@GET("publicised_groups/{userId}") - //Call getUserPublicisedGroups(@Path("userId") String userId); - - /** - * Request the publicised groups for user ids. - * - * @param params the request params - */ - @POST("publicised_groups") - Call getPublicisedGroups(@Body Map> params); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/LoginApi.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/LoginApi.java deleted file mode 100644 index ef9ea941..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/LoginApi.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.api; - -import com.google.gson.JsonObject; - -import im.vector.matrix.android.internal.legacy.RestClient; -import im.vector.matrix.android.internal.legacy.rest.model.Versions; -import im.vector.matrix.android.internal.legacy.rest.model.login.LoginFlowResponse; -import im.vector.matrix.android.internal.legacy.rest.model.login.LoginParams; -import im.vector.matrix.android.internal.legacy.rest.model.login.RegistrationParams; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.GET; -import retrofit2.http.POST; - -/** - * The login REST API. - */ -public interface LoginApi { - - /** - * Get the different login flows supported by the server. - */ - @GET(RestClient.URI_API_PREFIX_PATH + "versions") - Call versions(); - - /** - * Get the different login flows supported by the server. - */ - @GET(RestClient.URI_API_PREFIX_PATH_R0 + "login") - Call login(); - - /** - * Try to create an account - * - * @param params the registration params - */ - @POST(RestClient.URI_API_PREFIX_PATH_R0 + "register") - Call register(@Body RegistrationParams params); - - /** - * Pass params to the server for the current login phase. - * - * @param loginParams the login parameters - */ - @POST(RestClient.URI_API_PREFIX_PATH_R0 + "login") - Call login(@Body LoginParams loginParams); - - /** - * Invalidate the access token, so that it can no longer be used for authorization. - */ - @POST(RestClient.URI_API_PREFIX_PATH_R0 + "logout") - Call logout(); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/MediaScanApi.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/MediaScanApi.java deleted file mode 100644 index 6b30215f..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/MediaScanApi.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.rest.api; - -import im.vector.matrix.android.internal.legacy.rest.model.EncryptedMediaScanBody; -import im.vector.matrix.android.internal.legacy.rest.model.EncryptedMediaScanEncryptedBody; -import im.vector.matrix.android.internal.legacy.rest.model.MediaScanPublicKeyResult; -import im.vector.matrix.android.internal.legacy.rest.model.MediaScanResult; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.GET; -import retrofit2.http.POST; -import retrofit2.http.Path; - -/** - * The matrix content scanner REST API. - */ -public interface MediaScanApi { - /** - * Get the current public curve25519 key that the AV server is advertising. - */ - @GET("public_key") - Call getServerPublicKey(); - - /** - * Scan an unencrypted file. - * - * @param domain the server name - * @param mediaId the user id - */ - @GET("scan/{domain}/{mediaId}") - Call scanUnencrypted(@Path("domain") String domain, @Path("mediaId") String mediaId); - - /** - * Scan an encrypted file. - * - * @param encryptedMediaScanBody the encryption information required to decrypt the content before scanning it. - */ - @POST("scan_encrypted") - Call scanEncrypted(@Body EncryptedMediaScanBody encryptedMediaScanBody); - - /** - * Scan an encrypted file, sending an encrypted body. - * - * @param encryptedMediaScanEncryptedBody the encrypted encryption information required to decrypt the content before scanning it. - */ - @POST("scan_encrypted") - Call scanEncrypted(@Body EncryptedMediaScanEncryptedBody encryptedMediaScanEncryptedBody); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/PresenceApi.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/PresenceApi.java deleted file mode 100644 index 8a270484..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/PresenceApi.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.api; - -import im.vector.matrix.android.internal.legacy.rest.model.User; - -import retrofit2.Call; -import retrofit2.http.GET; -import retrofit2.http.Path; - -/** - * The presence REST API. - */ -public interface PresenceApi { - /** - * Get a user's presence state. - * - * @param userId the user id - */ - @GET("presence/{userId}/status") - Call presenceStatus(@Path("userId") String userId); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/ProfileApi.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/ProfileApi.java deleted file mode 100644 index 41d3fd8a..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/ProfileApi.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.api; - -import im.vector.matrix.android.internal.legacy.RestClient; -import im.vector.matrix.android.internal.legacy.rest.model.DeactivateAccountParams; -import im.vector.matrix.android.internal.legacy.rest.model.RequestEmailValidationParams; -import im.vector.matrix.android.internal.legacy.rest.model.RequestEmailValidationResponse; -import im.vector.matrix.android.internal.legacy.rest.model.RequestPhoneNumberValidationParams; -import im.vector.matrix.android.internal.legacy.rest.model.RequestPhoneNumberValidationResponse; -import im.vector.matrix.android.internal.legacy.rest.model.pid.AccountThreePidsResponse; -import im.vector.matrix.android.internal.legacy.rest.model.pid.AddThreePidsParams; -import im.vector.matrix.android.internal.legacy.rest.model.ChangePasswordParams; -import im.vector.matrix.android.internal.legacy.rest.model.pid.DeleteThreePidParams; -import im.vector.matrix.android.internal.legacy.rest.model.ForgetPasswordParams; -import im.vector.matrix.android.internal.legacy.rest.model.ForgetPasswordResponse; -import im.vector.matrix.android.internal.legacy.rest.model.User; -import im.vector.matrix.android.internal.legacy.rest.model.login.TokenRefreshParams; -import im.vector.matrix.android.internal.legacy.rest.model.login.TokenRefreshResponse; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.GET; -import retrofit2.http.POST; -import retrofit2.http.PUT; -import retrofit2.http.Path; - - -/** - * The profile REST API. - */ -public interface ProfileApi { - - /** - * Update a user's display name. - * - * @param userId the user id - * @param user the user object containing the new display name - */ - @PUT(RestClient.URI_API_PREFIX_PATH_R0 + "profile/{userId}/displayname") - Call displayname(@Path("userId") String userId, @Body User user); - - /** - * Get a user's display name. - * - * @param userId the user id - */ - @GET(RestClient.URI_API_PREFIX_PATH_R0 + "profile/{userId}/displayname") - Call displayname(@Path("userId") String userId); - - /** - * Update a user's avatar URL. - * - * @param userId the user id - * @param user the user object containing the new avatar url - */ - @PUT(RestClient.URI_API_PREFIX_PATH_R0 + "profile/{userId}/avatar_url") - Call avatarUrl(@Path("userId") String userId, @Body User user); - - /** - * Get a user's avatar URL. - * - * @param userId the user id - */ - @GET(RestClient.URI_API_PREFIX_PATH_R0 + "profile/{userId}/avatar_url") - Call avatarUrl(@Path("userId") String userId); - - /** - * Update the password - * - * @param passwordParams the new password - */ - @POST(RestClient.URI_API_PREFIX_PATH_R0 + "account/password") - Call updatePassword(@Body ChangePasswordParams passwordParams); - - /** - * Reset the password server side. - * - * @param params the forget password params - */ - @POST(RestClient.URI_API_PREFIX_PATH_R0 + "account/password/email/requestToken") - Call forgetPassword(@Body ForgetPasswordParams params); - - /** - * Deactivate the user account - * - * @param params the deactivate account params - */ - @POST(RestClient.URI_API_PREFIX_PATH_R0 + "account/deactivate") - Call deactivate(@Body DeactivateAccountParams params); - - /** - * Pass params to the server for the token refresh phase. - * - * @param refreshParams the refresh token parameters - */ - @POST(RestClient.URI_API_PREFIX_PATH_R0 + "tokenrefresh") - Call tokenrefresh(@Body TokenRefreshParams refreshParams); - - /** - * List all 3PIDs linked to the Matrix user account. - */ - @GET(RestClient.URI_API_PREFIX_PATH_R0 + "account/3pid") - Call threePIDs(); - - /** - * Add an 3Pid to a user - * - * @param params the params - */ - @POST(RestClient.URI_API_PREFIX_PATH_R0 + "account/3pid") - Call add3PID(@Body AddThreePidsParams params); - - /** - * Delete a 3Pid of a user - * - * @param params the params - */ - @POST(RestClient.URI_API_PREFIX_PATH_UNSTABLE + "account/3pid/delete") - Call delete3PID(@Body DeleteThreePidParams params); - - /** - * Request a validation token for an email - * Note: Proxies the identity server API validate/email/requestToken, but first checks that - * the given email address is not already associated with an account on this Home Server. - * - * @param params the parameters - */ - @POST(RestClient.URI_API_PREFIX_PATH_R0 + "account/3pid/email/requestToken") - Call requestEmailValidation(@Body RequestEmailValidationParams params); - - /** - * Request a validation token for an email being added during registration process - * Note: Proxies the identity server API validate/email/requestToken, but first checks that - * the given email address is not already associated with an account on this Home Server. - * - * @param params the parameters - */ - @POST(RestClient.URI_API_PREFIX_PATH_R0 + "register/email/requestToken") - Call requestEmailValidationForRegistration(@Body RequestEmailValidationParams params); - - /** - * Request a validation token for a phone number - * Note: Proxies the identity server API validate/msisdn/requestToken, but first checks that - * the given phone number is not already associated with an account on this Home Server. - * - * @param params the parameters - */ - @POST(RestClient.URI_API_PREFIX_PATH_R0 + "account/3pid/msisdn/requestToken") - Call requestPhoneNumberValidation(@Body RequestPhoneNumberValidationParams params); - - /** - * Request a validation token for a phone number being added during registration process - * Note: Proxies the identity server API validate/msisdn/requestToken, but first checks that - * the given phone number is not already associated with an account on this Home Server. - * - * @param params the parameters - */ - @POST(RestClient.URI_API_PREFIX_PATH_R0 + "register/msisdn/requestToken") - Call requestPhoneNumberValidationForRegistration(@Body RequestPhoneNumberValidationParams params); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/PushRulesApi.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/PushRulesApi.java deleted file mode 100644 index 251db04d..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/PushRulesApi.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.api; - -import com.google.gson.JsonElement; - -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.PushRulesResponse; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.DELETE; -import retrofit2.http.GET; -import retrofit2.http.PUT; -import retrofit2.http.Path; - -public interface PushRulesApi { - - /** - * Get all push rules - */ - @GET("pushrules/") - Call getAllRules(); - - /** - * Update the ruleID enable status - * - * @param kind the notification kind (sender, room...) - * @param ruleId the ruleId - * @param enable the new enable status - */ - @PUT("pushrules/global/{kind}/{ruleId}/enabled") - Call updateEnableRuleStatus(@Path("kind") String kind, @Path("ruleId") String ruleId, @Body Boolean enable); - - - /** - * Update the ruleID enable status - * - * @param kind the notification kind (sender, room...) - * @param ruleId the ruleId - * @param actions the actions - */ - @PUT("pushrules/global/{kind}/{ruleId}/actions") - Call updateRuleActions(@Path("kind") String kind, @Path("ruleId") String ruleId, @Body Object actions); - - - /** - * Update the ruleID enable status - * - * @param kind the notification kind (sender, room...) - * @param ruleId the ruleId - */ - @DELETE("pushrules/global/{kind}/{ruleId}") - Call deleteRule(@Path("kind") String kind, @Path("ruleId") String ruleId); - - /** - * Add the ruleID enable status - * - * @param kind the notification kind (sender, room...) - * @param ruleId the ruleId. - * @param rule the rule to add. - */ - @PUT("pushrules/global/{kind}/{ruleId}") - Call addRule(@Path("kind") String kind, @Path("ruleId") String ruleId, @Body JsonElement rule); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/PushersApi.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/PushersApi.java deleted file mode 100644 index e7e72b66..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/PushersApi.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2015 OpenMarket 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.matrix.android.internal.legacy.rest.api; - -import im.vector.matrix.android.internal.legacy.data.Pusher; -import im.vector.matrix.android.internal.legacy.rest.model.PushersResponse; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.GET; -import retrofit2.http.POST; - -/** - * The pusher API - */ -public interface PushersApi { - @POST("pushers/set") - Call set(@Body Pusher pusher); - - @GET("pushers") - Call get(); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/RoomsApi.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/RoomsApi.java deleted file mode 100644 index f9370133..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/RoomsApi.java +++ /dev/null @@ -1,410 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.api; - -import android.support.annotation.Nullable; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; - -import im.vector.matrix.android.internal.legacy.rest.model.BannedUser; -import im.vector.matrix.android.internal.legacy.rest.model.ChunkEvents; -import im.vector.matrix.android.internal.legacy.rest.model.CreateRoomParams; -import im.vector.matrix.android.internal.legacy.rest.model.CreateRoomResponse; -import im.vector.matrix.android.internal.legacy.rest.model.CreatedEvent; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.EventContext; -import im.vector.matrix.android.internal.legacy.rest.model.PowerLevels; -import im.vector.matrix.android.internal.legacy.rest.model.ReportContentParams; -import im.vector.matrix.android.internal.legacy.rest.model.RoomAliasDescription; -import im.vector.matrix.android.internal.legacy.rest.model.RoomDirectoryVisibility; -import im.vector.matrix.android.internal.legacy.rest.model.RoomMember; -import im.vector.matrix.android.internal.legacy.rest.model.TokensChunkEvents; -import im.vector.matrix.android.internal.legacy.rest.model.Typing; -import im.vector.matrix.android.internal.legacy.rest.model.User; -import im.vector.matrix.android.internal.legacy.rest.model.message.Message; -import im.vector.matrix.android.internal.legacy.rest.model.sync.RoomResponse; - -import java.util.Map; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.DELETE; -import retrofit2.http.GET; -import retrofit2.http.POST; -import retrofit2.http.PUT; -import retrofit2.http.Path; -import retrofit2.http.Query; - -/** - * The rooms REST API. - */ -public interface RoomsApi { - - /** - * Send an event to a room. - * - * @param txId the transaction Id - * @param roomId the room id - * @param eventType the event type - * @param content the event content - */ - @PUT("rooms/{roomId}/send/{eventType}/{txId}") - Call send(@Path("txId") String txId, @Path("roomId") String roomId, @Path("eventType") String eventType, @Body JsonObject content); - - /** - * Send a message to the specified room. - * - * @param txId the transaction Id - * @param roomId the room id - * @param message the message - */ - @PUT("rooms/{roomId}/send/m.room.message/{txId}") - Call sendMessage(@Path("txId") String txId, @Path("roomId") String roomId, @Body Message message); - - /** - * Update the power levels - * - * @param roomId the room id - * @param powerLevels the new power levels - */ - @PUT("rooms/{roomId}/state/m.room.power_levels") - Call setPowerLevels(@Path("roomId") String roomId, @Body PowerLevels powerLevels); - - /** - * Send a generic state events - * - * @param roomId the room id. - * @param stateEventType the state event type - * @param params the request parameters - */ - @PUT("rooms/{roomId}/state/{state_event_type}") - Call sendStateEvent(@Path("roomId") String roomId, @Path("state_event_type") String stateEventType, @Body Map params); - - /** - * Send a generic state events - * - * @param roomId the room id. - * @param stateEventType the state event type - * @param stateKey the state keys - * @param params the request parameters - */ - @PUT("rooms/{roomId}/state/{state_event_type}/{stateKey}") - Call sendStateEvent(@Path("roomId") String roomId, - @Path("state_event_type") String stateEventType, - @Path("stateKey") String stateKey, - @Body Map params); - - /** - * Looks up the contents of a state event in a room - * - * @param roomId the room id - * @param eventType the event type - */ - @GET("rooms/{roomId}/state/{eventType}") - Call getStateEvent(@Path("roomId") String roomId, @Path("eventType") String eventType); - - /** - * Looks up the contents of a state event in a room - * - * @param roomId the room id - * @param eventType the event type - * @param stateKey the key of the state to look up - */ - @GET("rooms/{roomId}/state/{eventType}/{stateKey}") - Call getStateEvent(@Path("roomId") String roomId, @Path("eventType") String eventType, @Path("stateKey") String stateKey); - - /** - * Invite a user to the given room. - * - * @param roomId the room id - * @param user a user object that just needs a user id - */ - @POST("rooms/{roomId}/invite") - Call invite(@Path("roomId") String roomId, @Body User user); - - /** - * Trigger an invitation with a parameters set. - * - * @param roomId the room id - * @param params the parameters - */ - @POST("rooms/{roomId}/invite") - Call invite(@Path("roomId") String roomId, @Body Map params); - - /** - * Join the given room. - * - * @param roomId the room id - * @param content the request body - */ - @POST("rooms/{roomId}/join") - Call join(@Path("roomId") String roomId, @Body JsonObject content); - - /** - * Join the room with a room id or an alias. - * - * @param roomAliasOrId a room alias (or room id) - * @param params the extra join param - */ - @POST("join/{roomAliasOrId}") - Call joinRoomByAliasOrId(@Path("roomAliasOrId") String roomAliasOrId, @Body Map params); - - /** - * Leave the given room. - * - * @param roomId the room id - * @param content the request body - */ - @POST("rooms/{roomId}/leave") - Call leave(@Path("roomId") String roomId, @Body JsonObject content); - - /** - * Forget the given room. - * - * @param roomId the room id - * @param content the request body - */ - @POST("rooms/{roomId}/forget") - Call forget(@Path("roomId") String roomId, @Body JsonObject content); - - /** - * Ban a user from the given room. - * - * @param roomId the room id - * @param user the banned user object (userId and reason for ban) - */ - @POST("rooms/{roomId}/ban") - Call ban(@Path("roomId") String roomId, @Body BannedUser user); - - /** - * unban a user from the given room. - * - * @param roomId the room id - * @param user the banned user object (userId and reason for unban) - */ - @POST("rooms/{roomId}/unban") - Call unban(@Path("roomId") String roomId, @Body BannedUser user); - - /** - * Change the membership state for a user in a room. - * - * @param roomId the room id - * @param userId the user id - * @param member object containing the membership field to set - */ - @PUT("rooms/{roomId}/state/m.room.member/{userId}") - Call updateRoomMember(@Path("roomId") String roomId, @Path("userId") String userId, @Body RoomMember member); - - /** - * Update the typing notification - * - * @param roomId the room id - * @param userId the user id - * @param typing the typing notification - */ - @PUT("rooms/{roomId}/typing/{userId}") - Call setTypingNotification(@Path("roomId") String roomId, @Path("userId") String userId, @Body Typing typing); - - /** - * Create a room. - * - * @param createRoomRequest the creation room request - */ - @POST("createRoom") - Call createRoom(@Body CreateRoomParams createRoomRequest); - - /** - * Get a list of messages starting from a reference. - * - * @param roomId the room id - * @param from the token identifying where to start. Required. - * @param dir The direction to return messages from. Required. - * @param limit the maximum number of messages to retrieve. Optional. - * @param filter A JSON RoomEventFilter to filter returned events with. Optional. - */ - @GET("rooms/{roomId}/messages") - Call getRoomMessagesFrom(@Path("roomId") String roomId, - @Query("from") String from, - @Query("dir") String dir, - @Query("limit") int limit, - @Nullable @Query("filter") String filter); - - /** - * Get the initial information concerning a specific room. - * - * @param roomId the room id - * @param limit the maximum number of messages to retrieve - */ - @GET("rooms/{roomId}/initialSync") - Call initialSync(@Path("roomId") String roomId, @Query("limit") int limit); - - /** - * Get the context surrounding an event. - * - * @param roomId the room id - * @param eventId the event Id - * @param limit the maximum number of messages to retrieve - * @param filter A JSON RoomEventFilter to filter returned events with. Optional. - */ - @GET("rooms/{roomId}/context/{eventId}") - Call getContextOfEvent(@Path("roomId") String roomId, - @Path("eventId") String eventId, - @Query("limit") int limit, - @Nullable @Query("filter") String filter); - - /** - * Retrieve an event from its room id / events id - * - * @param roomId the room id - * @param eventId the event Id - */ - @GET("rooms/{roomId}/event/{eventId}") - Call getEvent(@Path("roomId") String roomId, @Path("eventId") String eventId); - - /** - * Redact an event from the room>. - * - * @param roomId the room id - * @param eventId the event id of the event to redact - * @param reason the reason - */ - @POST("rooms/{roomId}/redact/{eventId}") - Call redactEvent(@Path("roomId") String roomId, @Path("eventId") String eventId, @Body JsonObject reason); - - /** - * Report an event content. - * - * @param roomId the room id - * @param eventId the event id of the event to redact - * @param param the request parameters - */ - @POST("rooms/{roomId}/report/{eventId}") - Call reportEvent(@Path("roomId") String roomId, @Path("eventId") String eventId, @Body ReportContentParams param); - - /** - * Send a read receipt. - * - * @param roomId the room id - * @param EventId the latest eventId - * @param content the event content - */ - @POST("rooms/{roomId}/receipt/m.read/{eventId}") - Call sendReadReceipt(@Path("roomId") String roomId, @Path("eventId") String EventId, @Body JsonObject content); - - /** - * Send read markers. - * - * @param roomId the room id - * @param markers the read markers - */ - @POST("rooms/{roomId}/read_markers") - Call sendReadMarker(@Path("roomId") String roomId, @Body Map markers); - - /** - * Add a tag to a room - * - * @param userId the userId - * @param roomId the room id - * @param tag the new room tag - * @param content the event content - */ - @PUT("user/{userId}/rooms/{roomId}/tags/{tag}") - Call addTag(@Path("userId") String userId, @Path("roomId") String roomId, @Path("tag") String tag, @Body Map content); - - /** - * Remove a tag to a room - * - * @param userId the userId - * @param roomId the room id - * @param tag the new room tag - */ - @DELETE("user/{userId}/rooms/{roomId}/tags/{tag}") - Call removeTag(@Path("userId") String userId, @Path("roomId") String roomId, @Path("tag") String tag); - - /** - * Update a dedicated account data field - * - * @param userId the userId - * @param roomId the room id - * @param subPath the url sub path - * @param content the event content - */ - @PUT("user/{userId}/rooms/{roomId}/account_data/{tag}") - Call updateAccountData(@Path("userId") String userId, - @Path("roomId") String roomId, - @Path("tag") String subPath, - @Body Map content); - - /** - * Get the room ID associated to the room alias. - * - * @param roomAlias the room alias. - */ - @GET("directory/room/{roomAlias}") - Call getRoomIdByAlias(@Path("roomAlias") String roomAlias); - - /** - * Associate a room alias with a room ID. - * - * @param roomAlias the room alias. - * @param description the alias description containing the room ID - */ - @PUT("directory/room/{roomAlias}") - Call setRoomIdByAlias(@Path("roomAlias") String roomAlias, @Body RoomAliasDescription description); - - /** - * Get the room ID corresponding to this room alias. - * - * @param roomAlias the room alias. - */ - @DELETE("directory/room/{roomAlias}") - Call removeRoomAlias(@Path("roomAlias") String roomAlias); - - /** - * Set the visibility of the given room in the list directory. If the visibility is set to public, the room - * name is listed among the directory list. - * - * @param roomId the room id where to apply the request - * @param roomDirectoryVisibility the put params containing the new "visibility" field - */ - @PUT("directory/list/room/{roomId}") - Call setRoomDirectoryVisibility(@Path("roomId") String roomId, RoomDirectoryVisibility roomDirectoryVisibility); - - /** - * Get the visibility of the given room in the list directory. - * - * @param roomId the room id where to apply the request - */ - @GET("directory/list/room/{roomId}") - Call getRoomDirectoryVisibility(@Path("roomId") String roomId); - - /** - * Get all members of a room - * - * @param roomId the room id where to get the members - * @param syncToken the sync token (optional) - * @param membership to include only one type of membership (optional) - * @param notMembership to exclude one type of membership (optional) - */ - @GET("rooms/{roomId}/members") - Call getMembers(@Path("roomId") String roomId, - @Nullable @Query("at") String syncToken, - @Nullable @Query("membership") String membership, - @Nullable @Query("not_membership") String notMembership); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/ThirdPidApi.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/ThirdPidApi.java deleted file mode 100644 index 57203b4f..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/api/ThirdPidApi.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.rest.api; - -import im.vector.matrix.android.internal.legacy.rest.model.BulkLookupParams; -import im.vector.matrix.android.internal.legacy.rest.model.BulkLookupResponse; -import im.vector.matrix.android.internal.legacy.rest.model.RequestEmailValidationParams; -import im.vector.matrix.android.internal.legacy.rest.model.pid.PidResponse; - -import java.util.Map; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.GET; -import retrofit2.http.POST; -import retrofit2.http.Path; -import retrofit2.http.Query; - -public interface ThirdPidApi { - - /** - * Get the 3rd party id from a medium - * - * @param address the address. - * @param medium the medium. - */ - @GET("lookup") - Call lookup3Pid(@Query("address") String address, - @Query("medium") String medium); - - /** - * Request a bunch of 3PIDs - * - * @param body the body request - */ - @POST("bulk_lookup") - Call bulkLookup(@Body BulkLookupParams body); - - - /** - * Request the ownership validation of an email address or a phone number previously set - * by {@link ProfileApi#requestEmailValidation(RequestEmailValidationParams)} - * - * @param medium the medium of the 3pid - * @param token the token generated by the requestToken call - * @param clientSecret the client secret which was supplied in the requestToken call - * @param sid the sid for the session - */ - @POST("validate/{medium}/submitToken") - Call> requestOwnershipValidation(@Path("medium") String medium, - @Query("token") String token, - @Query("client_secret") String clientSecret, - @Query("sid") String sid); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/ApiCallback.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/ApiCallback.java deleted file mode 100644 index 8b9d7b4a..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/ApiCallback.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.callback; - -/** - * Generic callback interface for asynchronously returning information. - * - * @param the type of information to return on success - */ -public interface ApiCallback extends SuccessCallback, ApiFailureCallback { - -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/ApiFailureCallback.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/ApiFailureCallback.java deleted file mode 100644 index 29b04200..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/ApiFailureCallback.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.callback; - -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; - -/** - * Callback interface for asynchronously returning API call failures. - */ -public interface ApiFailureCallback { - - /** - * Called if there is a network error. - * - * @param e the exception - */ - void onNetworkError(Exception e); - - /** - * Called in case of a Matrix error. - * - * @param e the Matrix error - */ - void onMatrixError(MatrixError e); - - /** - * Called for some other type of error. - * - * @param e the exception - */ - void onUnexpectedError(Exception e); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/DefaultRetrofit2CallbackWrapper.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/DefaultRetrofit2CallbackWrapper.java deleted file mode 100644 index 271e8de7..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/DefaultRetrofit2CallbackWrapper.java +++ /dev/null @@ -1,48 +0,0 @@ -package im.vector.matrix.android.internal.legacy.rest.callback; - -import im.vector.matrix.android.internal.legacy.rest.model.HttpError; -import im.vector.matrix.android.internal.legacy.rest.model.HttpException; - -import java.io.IOException; - -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; - -public class DefaultRetrofit2CallbackWrapper - implements Callback, DefaultRetrofit2ResponseHandler.Listener { - - private final ApiCallback apiCallback; - - public DefaultRetrofit2CallbackWrapper(ApiCallback apiCallback) { - this.apiCallback = apiCallback; - } - - public ApiCallback getApiCallback() { - return apiCallback; - } - - @Override public void onResponse(Call call, Response response) { - try { - handleResponse(response); - } catch (IOException e) { - apiCallback.onUnexpectedError(e); - } - } - - private void handleResponse(Response response) throws IOException { - DefaultRetrofit2ResponseHandler.handleResponse(response, this); - } - - @Override public void onFailure(Call call, Throwable t) { - apiCallback.onNetworkError((Exception) t); - } - - @Override public void onSuccess(Response response) { - apiCallback.onSuccess(response.body()); - } - - @Override public void onHttpError(HttpError httpError) { - apiCallback.onNetworkError(new HttpException(httpError)); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/DefaultRetrofit2ResponseHandler.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/DefaultRetrofit2ResponseHandler.java deleted file mode 100644 index 74b5c645..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/DefaultRetrofit2ResponseHandler.java +++ /dev/null @@ -1,24 +0,0 @@ -package im.vector.matrix.android.internal.legacy.rest.callback; - -import im.vector.matrix.android.internal.legacy.rest.model.HttpError; - -import java.io.IOException; - -import retrofit2.Response; - -public class DefaultRetrofit2ResponseHandler { - public static void handleResponse(Response response, Listener listener) - throws IOException { - if (response.isSuccessful()) { - listener.onSuccess(response); - } else { - String errorBody = response.errorBody().string(); - listener.onHttpError(new HttpError(errorBody, response.code())); - } - } - - public interface Listener { - void onSuccess(Response response); - void onHttpError(HttpError httpError); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/RestAdapterCallback.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/RestAdapterCallback.java deleted file mode 100644 index 34808313..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/RestAdapterCallback.java +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.callback; - -import com.google.gson.JsonSyntaxException; -import com.google.gson.stream.MalformedJsonException; - -import im.vector.matrix.android.internal.legacy.rest.model.HttpError; -import im.vector.matrix.android.internal.legacy.rest.model.HttpException; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.util.JsonUtils; -import im.vector.matrix.android.internal.legacy.util.Log; -import im.vector.matrix.android.internal.legacy.util.UnsentEventsManager; - -import java.io.IOException; - -import okhttp3.ResponseBody; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; - -public class RestAdapterCallback implements Callback { - - private static final String LOG_TAG = "RestAdapterCallback"; - - /** - * Callback when a request failed after a network error. - * This callback should manage the request auto resent. - */ - public interface RequestRetryCallBack { - void onRetry(); - } - - // the event description - private final String mEventDescription; - - // the callback - // FIXME It should be safer if the type was ApiCallback, else onSuccess() has to be overridden - private final ApiCallback mApiCallback; - - // the retry callback - private final RequestRetryCallBack mRequestRetryCallBack; - - // the unsent events manager - private final UnsentEventsManager mUnsentEventsManager; - - // true to do not test if he event time line when sending again - // the request when a data connection is retrieved. - private final boolean mIgnoreEventTimeLifeInOffline; - - /** - * Constructor with unsent events management - * - * @param description the event description - * @param unsentEventsManager the unsent events manager - * @param apiCallback the callback - * @param requestRetryCallBack the retry callback - */ - public RestAdapterCallback(String description, - UnsentEventsManager unsentEventsManager, - ApiCallback apiCallback, - RequestRetryCallBack requestRetryCallBack) { - this(description, unsentEventsManager, false, apiCallback, requestRetryCallBack); - } - - /** - * Constructor with unsent events management - * - * @param description the event description - * @param ignoreEventTimeLifeOffline true to ignore the event time when resending the event. - * @param unsentEventsManager the unsent events manager - * @param apiCallback the callback - * @param requestRetryCallBack the retry callback - */ - public RestAdapterCallback(String description, - UnsentEventsManager unsentEventsManager, - boolean ignoreEventTimeLifeOffline, - ApiCallback apiCallback, - RequestRetryCallBack requestRetryCallBack) { - if (null != description) { - Log.d(LOG_TAG, "Trigger the event [" + description + "]"); - } - - mEventDescription = description; - mIgnoreEventTimeLifeInOffline = ignoreEventTimeLifeOffline; - mApiCallback = apiCallback; - mRequestRetryCallBack = requestRetryCallBack; - mUnsentEventsManager = unsentEventsManager; - } - - /** - * Notify the {@link UnsentEventsManager} that the event has been successfully sent. - * This method must be called each time a REST call succeed, in order to warn - * the {@link UnsentEventsManager} to send the next unsent events. - */ - protected void onEventSent() { - if (null != mUnsentEventsManager) { - try { - // some users reported that their devices were connected - // whereas this receiver was not called - if (!mUnsentEventsManager.getNetworkConnectivityReceiver().isConnected()) { - Log.d(LOG_TAG, "## onEventSent(): request succeed, while network seen as disconnected => ask ConnectivityReceiver to dispatch info"); - mUnsentEventsManager.getNetworkConnectivityReceiver().checkNetworkConnection(mUnsentEventsManager.getContext()); - } - - mUnsentEventsManager.onEventSent(mApiCallback); - } catch (Exception e) { - Log.e(LOG_TAG, "## onEventSent(): Exception " + e.getMessage(), e); - } - } - } - - @Override - public void onResponse(Call call, final Response response) { - try { - handleResponse(response); - } catch (IOException e) { - onFailure(call, e); - } - } - - private void handleResponse(final Response response) throws IOException { - DefaultRetrofit2ResponseHandler.handleResponse( - response, - new DefaultRetrofit2ResponseHandler.Listener() { - @Override - public void onSuccess(Response response) { - success(response.body(), response); - } - - @Override - public void onHttpError(HttpError httpError) { - failure(response, new HttpException(httpError)); - } - } - ); - } - - @Override - public void onFailure(Call call, Throwable t) { - failure(null, (Exception) t); - } - - public void success(T t, Response response) { - if (null != mEventDescription) { - Log.d(LOG_TAG, "## Succeed() : [" + mEventDescription + "]"); - } - - // add try catch to prevent application crashes while managing destroyed object - try { - onEventSent(); - - if (null != mApiCallback) { - try { - mApiCallback.onSuccess(t); - } catch (Exception e) { - Log.e(LOG_TAG, "## succeed() : onSuccess failed " + e.getMessage(), e); - mApiCallback.onUnexpectedError(e); - } - } - } catch (Exception e) { - // privacy - Log.e(LOG_TAG, "## succeed(): Exception " + e.getMessage(), e); - } - } - - /** - * Default failure implementation that calls the right error handler - * - * @param response the retrofit response - * @param exception the retrofit exception - */ - public void failure(Response response, Exception exception) { - if (null != mEventDescription) { - String error = exception != null - ? exception.getMessage() - : (response != null ? response.message() : "unknown"); - - Log.d(LOG_TAG, "## failure(): [" + mEventDescription + "]" + " with error " + error); - } - - boolean retry = true; - - if (null != response) { - retry = (response.code() < 400) || (response.code() > 500); - } - - // do not retry if the response format is not the expected one. - retry &= (null == exception.getCause()) - || !(exception.getCause() instanceof MalformedJsonException || exception.getCause() instanceof JsonSyntaxException); - - if (retry && (null != mUnsentEventsManager)) { - Log.d(LOG_TAG, "Add it to the UnsentEventsManager"); - mUnsentEventsManager.onEventSendingFailed(mEventDescription, mIgnoreEventTimeLifeInOffline, response, exception, mApiCallback, - mRequestRetryCallBack); - } else { - if (exception != null && exception instanceof IOException) { - try { - if (null != mApiCallback) { - try { - mApiCallback.onNetworkError(exception); - } catch (Exception e) { - Log.e(LOG_TAG, "## failure(): onNetworkError " + exception.getLocalizedMessage(), exception); - } - } - } catch (Exception e) { - // privacy - //Log.e(LOG_TAG, "Exception NetworkError " + e.getMessage() + " while managing " + error.getUrl()); - Log.e(LOG_TAG, "## failure(): NetworkError " + e.getMessage(), e); - } - } else { - // Try to convert this into a Matrix error - MatrixError mxError; - try { - HttpError error = ((HttpException) exception).getHttpError(); - ResponseBody errorBody = response.errorBody(); - - String bodyAsString = error.getErrorBody(); - mxError = JsonUtils.getGson(false).fromJson(bodyAsString, MatrixError.class); - - mxError.mStatus = response.code(); - mxError.mReason = response.message(); - mxError.mErrorBodyMimeType = errorBody.contentType(); - mxError.mErrorBody = errorBody; - mxError.mErrorBodyAsString = bodyAsString; - } catch (Exception e) { - mxError = null; - } - if (mxError != null) { - if (MatrixError.LIMIT_EXCEEDED.equals(mxError.errcode) && (null != mUnsentEventsManager)) { - mUnsentEventsManager.onEventSendingFailed(mEventDescription, mIgnoreEventTimeLifeInOffline, response, exception, mApiCallback, - mRequestRetryCallBack); - } else if (MatrixError.isConfigurationErrorCode(mxError.errcode) && (null != mUnsentEventsManager)) { - mUnsentEventsManager.onConfigurationErrorCode(mxError.errcode, mEventDescription); - } else { - try { - if (null != mApiCallback) { - mApiCallback.onMatrixError(mxError); - } - } catch (Exception e) { - // privacy - //Log.e(LOG_TAG, "Exception MatrixError " + e.getMessage() + " while managing " + error.getUrl()); - Log.e(LOG_TAG, "## failure(): MatrixError " + e.getMessage(), e); - } - } - } else { - try { - if (null != mApiCallback) { - mApiCallback.onUnexpectedError(exception); - } - } catch (Exception e) { - // privacy - //Log.e(LOG_TAG, "Exception UnexpectedError " + e.getMessage() + " while managing " + error.getUrl()); - Log.e(LOG_TAG, "## failure(): UnexpectedError " + e.getMessage(), e); - } - } - } - } - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/SimpleApiCallback.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/SimpleApiCallback.java deleted file mode 100644 index c4a5ff29..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/SimpleApiCallback.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.callback; - -import android.app.Activity; -import android.content.Context; - -import im.vector.matrix.android.internal.legacy.util.Log; - -import android.view.View; -import android.widget.Toast; - -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; - -/** - * A stub implementation of {@link ApiCallback} which only chosen callbacks - * can be implemented. - */ -public abstract class SimpleApiCallback implements ApiCallback { - - private static final String LOG_TAG = "SimpleApiCallback"; - - private Activity mActivity; - - private Context mContext = null; - private View mPostView = null; - - /** - * Failure callback to pass on failures to. - */ - private ApiFailureCallback failureCallback = null; - - /** - * Constructor - */ - public SimpleApiCallback() { - } - - /** - * Constructor - * - * @param activity The context. - */ - public SimpleApiCallback(Activity activity) { - mActivity = activity; - } - - /** - * Constructor - * - * @param context The context. - * @param postOnView the view to post the code to execute - */ - public SimpleApiCallback(Context context, View postOnView) { - mContext = context; - mPostView = postOnView; - } - - /** - * Constructor to delegate failure callback to another object. This allows us to stack failure callback implementations - * in a decorator-type approach. - * - * @param failureCallback the failure callback implementation to delegate to - */ - public SimpleApiCallback(ApiFailureCallback failureCallback) { - this.failureCallback = failureCallback; - } - - private void displayToast(final String message) { - if (null != mActivity) { - mActivity.runOnUiThread(new Runnable() { - @Override - public void run() { - Toast.makeText(mActivity, message, Toast.LENGTH_SHORT).show(); - } - }); - } else if ((null != mContext) && (null != mPostView)) { - mPostView.post(new Runnable() { - @Override - public void run() { - Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show(); - } - }); - } - } - - @Override - public void onNetworkError(Exception e) { - if (failureCallback != null) { - try { - failureCallback.onNetworkError(e); - } catch (Exception exception) { - Log.e(LOG_TAG, "## onNetworkError() failed" + exception.getMessage(), exception); - } - } else { - displayToast("Network Error"); - } - } - - @Override - public void onMatrixError(final MatrixError e) { - if (failureCallback != null) { - try { - failureCallback.onMatrixError(e); - } catch (Exception exception) { - Log.e(LOG_TAG, "## onMatrixError() failed" + exception.getMessage(), exception); - } - } else { - displayToast("Matrix Error : " + e.getLocalizedMessage()); - } - } - - @Override - public void onUnexpectedError(final Exception e) { - if (failureCallback != null) { - try { - failureCallback.onUnexpectedError(e); - } catch (Exception exception) { - Log.e(LOG_TAG, "## onUnexpectedError() failed" + exception.getMessage(), exception); - } - } else { - displayToast(e.getLocalizedMessage()); - } - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/SuccessCallback.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/SuccessCallback.java deleted file mode 100644 index 1e624b69..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/SuccessCallback.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.rest.callback; - -public interface SuccessCallback { - /** - * Called if the result is successful. - * - * @param info the returned information - */ - void onSuccess(T info); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/ToastErrorHandler.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/ToastErrorHandler.java deleted file mode 100644 index cdfbad4e..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/callback/ToastErrorHandler.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.callback; - -import android.content.Context; -import android.widget.Toast; - -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; - -/** - * Failure callback that shows different toast messages. - */ -public class ToastErrorHandler implements ApiFailureCallback { - - private final Context context; - private final String msgPrefix; - - /** - * Constructor with context for the toast messages and a common prefix for messages. - * - * @param context the context - needed for toast - * @param msgPrefix the message prefix - */ - public ToastErrorHandler(Context context, String msgPrefix) { - this.context = context; - this.msgPrefix = msgPrefix; - } - - @Override - public void onNetworkError(Exception e) { - Toast.makeText(context, appendPrefix("Connection error"), Toast.LENGTH_LONG).show(); - } - - @Override - public void onMatrixError(MatrixError e) { - Toast.makeText(context, appendPrefix(e.getLocalizedMessage()), Toast.LENGTH_LONG).show(); - } - - @Override - public void onUnexpectedError(Exception e) { - Toast.makeText(context, appendPrefix(null), Toast.LENGTH_LONG).show(); - } - - String appendPrefix(String text) { - return (text == null) ? msgPrefix : msgPrefix + ": " + text; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/AccountDataRestClient.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/AccountDataRestClient.java deleted file mode 100644 index 74b6c109..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/AccountDataRestClient.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2015 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.client; - -import java.util.HashMap; -import java.util.Map; - -import im.vector.matrix.android.api.auth.data.SessionParams; -import im.vector.matrix.android.internal.legacy.RestClient; -import im.vector.matrix.android.internal.legacy.rest.api.AccountDataApi; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.RestAdapterCallback; - -public class AccountDataRestClient extends RestClient { - /** - * Account data types - */ - public static final String ACCOUNT_DATA_TYPE_IGNORED_USER_LIST = "m.ignored_user_list"; - public static final String ACCOUNT_DATA_TYPE_DIRECT_MESSAGES = "m.direct"; - public static final String ACCOUNT_DATA_TYPE_PREVIEW_URLS = "org.matrix.preview_urls"; - public static final String ACCOUNT_DATA_TYPE_WIDGETS = "m.widgets"; - - /** - * Account data keys - */ - public static final String ACCOUNT_DATA_KEY_IGNORED_USERS = "ignored_users"; - public static final String ACCOUNT_DATA_KEY_URL_PREVIEW_DISABLE = "disable"; - - /** - * {@inheritDoc} - */ - public AccountDataRestClient(SessionParams sessionParams) { - super(sessionParams, AccountDataApi.class, RestClient.URI_API_PREFIX_PATH_R0, false); - } - - /** - * Set some account_data for the client. - * - * @param userId the user id - * @param type the account data type. - * @param params the put params. - * @param callback the asynchronous callback called when finished - */ - public void setAccountData(final String userId, final String type, final Object params, final ApiCallback callback) { - // privacy - //final String description = "setAccountData userId : " + userId + " type " + type + " params " + params; - final String description = "setAccountData userId : " + userId + " type " + type; - - mApi.setAccountData(userId, type, params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - setAccountData(userId, type, params, callback); - } - })); - } - - /** - * Gets a bearer token from the homeserver that the user can - * present to a third party in order to prove their ownership - * of the Matrix account they are logged into. - * - * @param userId the user id - * @param callback the asynchronous callback called when finished - */ - public void openIdToken(final String userId, final ApiCallback> callback) { - final String description = "openIdToken userId : " + userId; - - mApi.openIdToken(userId, new HashMap<>()) - .enqueue(new RestAdapterCallback>(description, mUnsentEventsManager, callback, - new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - openIdToken(userId, callback); - } - })); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/CallRestClient.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/CallRestClient.java deleted file mode 100644 index f7873b33..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/CallRestClient.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2015 OpenMarket 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.matrix.android.internal.legacy.rest.client; - -import com.google.gson.JsonObject; - -import im.vector.matrix.android.api.auth.data.SessionParams; -import im.vector.matrix.android.internal.legacy.RestClient; -import im.vector.matrix.android.internal.legacy.rest.api.CallRulesApi; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.DefaultRetrofit2CallbackWrapper; - -public class CallRestClient extends RestClient { - - /** - * {@inheritDoc} - */ - public CallRestClient(SessionParams sessionParams) { - super(sessionParams, CallRulesApi.class, RestClient.URI_API_PREFIX_PATH_R0, false); - } - - public void getTurnServer(final ApiCallback callback) { - mApi.getTurnServer().enqueue(new DefaultRetrofit2CallbackWrapper<>(callback)); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/CryptoRestClient.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/CryptoRestClient.java deleted file mode 100644 index 08472f88..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/CryptoRestClient.java +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.client; - -import android.text.TextUtils; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; - -import im.vector.matrix.android.api.auth.data.SessionParams; -import im.vector.matrix.android.internal.legacy.RestClient; -import im.vector.matrix.android.internal.legacy.crypto.data.MXKey; -import im.vector.matrix.android.internal.legacy.crypto.data.MXUsersDevicesMap; -import im.vector.matrix.android.internal.legacy.rest.api.CryptoApi; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.RestAdapterCallback; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.KeyChangesResponse; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.KeysClaimResponse; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.KeysQueryResponse; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.KeysUploadResponse; -import im.vector.matrix.android.internal.legacy.rest.model.pid.DeleteDeviceParams; -import im.vector.matrix.android.internal.legacy.rest.model.sync.DevicesListResponse; -import im.vector.matrix.android.internal.legacy.util.JsonUtils; -import im.vector.matrix.android.internal.legacy.util.Log; -import retrofit2.Response; - -public class CryptoRestClient extends RestClient { - - private static final String LOG_TAG = CryptoRestClient.class.getSimpleName(); - - /** - * {@inheritDoc} - */ - public CryptoRestClient(SessionParams sessionParams) { - super(sessionParams, CryptoApi.class, URI_API_PREFIX_PATH_UNSTABLE, false, false); - } - - /** - * Upload device and/or one-time keys. - * - * @param deviceKeys the device keys to send. - * @param oneTimeKeys the one-time keys to send. - * @param deviceId he explicit device_id to use for upload (default is to use the same as that used during auth). - * @param callback the asynchronous callback - */ - public void uploadKeys(final Map deviceKeys, - final Map oneTimeKeys, - final String deviceId, - final ApiCallback callback) { - final String description = "uploadKeys"; - - String encodedDeviceId = JsonUtils.convertToUTF8(deviceId); - Map params = new HashMap<>(); - - if (null != deviceKeys) { - params.put("device_keys", deviceKeys); - } - - if (null != oneTimeKeys) { - params.put("one_time_keys", oneTimeKeys); - } - - if (!TextUtils.isEmpty(encodedDeviceId)) { - mApi.uploadKeys(encodedDeviceId, params) - .enqueue(new RestAdapterCallback(description, null, callback, - new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - uploadKeys(deviceKeys, oneTimeKeys, deviceId, callback); - } - })); - } else { - mApi.uploadKeys(params) - .enqueue(new RestAdapterCallback(description, null, callback, - new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - uploadKeys(deviceKeys, oneTimeKeys, deviceId, callback); - } - })); - } - } - - /** - * Download device keys. - * - * @param userIds list of users to get keys for. - * @param token the up-to token - * @param callback the asynchronous callback - */ - public void downloadKeysForUsers(final List userIds, final String token, final ApiCallback callback) { - final String description = "downloadKeysForUsers"; - - Map> downloadQuery = new HashMap<>(); - - if (null != userIds) { - for (String userId : userIds) { - downloadQuery.put(userId, new HashMap()); - } - } - - Map parameters = new HashMap<>(); - parameters.put("device_keys", downloadQuery); - - if (!TextUtils.isEmpty(token)) { - parameters.put("token", token); - } - - mApi.downloadKeysForUsers(parameters) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, - new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - downloadKeysForUsers(userIds, token, callback); - } - })); - } - - /** - * Claim one-time keys. - * - * @param usersDevicesKeyTypesMap a list of users, devices and key types to retrieve keys for. - * @param callback the asynchronous callback - */ - public void claimOneTimeKeysForUsersDevices( - final MXUsersDevicesMap usersDevicesKeyTypesMap, - final ApiCallback> callback) { - final String description = "claimOneTimeKeysForUsersDevices"; - - Map params = new HashMap<>(); - params.put("one_time_keys", usersDevicesKeyTypesMap.getMap()); - - mApi.claimOneTimeKeysForUsersDevices(params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, - new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - claimOneTimeKeysForUsersDevices(usersDevicesKeyTypesMap, callback); - } - }) { - @Override - public void success(KeysClaimResponse keysClaimResponse, Response response) { - onEventSent(); - - Map> map = new HashMap<>(); - - if (null != keysClaimResponse.oneTimeKeys) { - for (String userId : keysClaimResponse.oneTimeKeys.keySet()) { - Map>> mapByUserId = keysClaimResponse.oneTimeKeys.get(userId); - - Map keysMap = new HashMap<>(); - - for (String deviceId : mapByUserId.keySet()) { - try { - keysMap.put(deviceId, new MXKey(mapByUserId.get(deviceId))); - } catch (Exception e) { - Log.e(LOG_TAG, "## claimOneTimeKeysForUsersDevices : fail to create a MXKey " + e.getMessage(), e); - } - } - - if (keysMap.size() != 0) { - map.put(userId, keysMap); - } - } - } - - callback.onSuccess(new MXUsersDevicesMap<>(map)); - } - }); - } - - /** - * Send an event to a specific list of devices - * - * @param eventType the type of event to send - * @param contentMap content to send. Map from user_id to device_id to content dictionary. - * @param callback the asynchronous callback. - */ - public void sendToDevice(final String eventType, - final MXUsersDevicesMap> contentMap, final ApiCallback callback) { - sendToDevice(eventType, contentMap, (new Random()).nextInt(Integer.MAX_VALUE) + "", callback); - } - - /** - * Send an event to a specific list of devices - * - * @param eventType the type of event to send - * @param contentMap content to send. Map from user_id to device_id to content dictionary. - * @param transactionId the transactionId - * @param callback the asynchronous callback. - */ - public void sendToDevice(final String eventType, - final MXUsersDevicesMap> contentMap, final String transactionId, - final ApiCallback callback) { - final String description = "sendToDevice " + eventType; - - Map content = new HashMap<>(); - content.put("messages", contentMap.getMap()); - - mApi.sendToDevice(eventType, transactionId, content) - .enqueue(new RestAdapterCallback(description, null, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - sendToDevice(eventType, contentMap, callback); - } - })); - } - - /** - * Retrieves the devices informaty - * - * @param callback the asynchronous callback. - */ - public void getDevices(final ApiCallback callback) { - final String description = "getDevicesListInfo"; - - mApi.getDevices() - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, - new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getDevices(callback); - } - })); - } - - /** - * Delete a device. - * - * @param deviceId the device id - * @param params the deletion parameters - * @param callback the asynchronous callback - */ - public void deleteDevice(final String deviceId, final DeleteDeviceParams params, - final ApiCallback callback) { - final String description = "deleteDevice"; - - mApi.deleteDevice(deviceId, params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - deleteDevice(deviceId, params, callback); - } - })); - } - - /** - * Set a device name. - * - * @param deviceId the device id - * @param deviceName the device name - * @param callback the asynchronous callback - */ - public void setDeviceName(final String deviceId, final String deviceName, - final ApiCallback callback) { - final String description = "setDeviceName"; - - Map params = new HashMap<>(); - params.put("display_name", TextUtils.isEmpty(deviceName) ? "" : deviceName); - - mApi.updateDeviceInfo(deviceId, params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - setDeviceName(deviceId, deviceName, callback); - } - })); - } - - /** - * Get the update devices list from two sync token. - * - * @param from the start token. - * @param to the up-to token. - * @param callback the asynchronous callback - */ - public void getKeyChanges(final String from, final String to, - final ApiCallback callback) { - final String description = "getKeyChanges"; - - mApi.getKeyChanges(from, to) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, - new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getKeyChanges(from, to, callback); - } - })); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/EventsRestClient.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/EventsRestClient.java deleted file mode 100644 index b251ba47..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/EventsRestClient.java +++ /dev/null @@ -1,603 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.client; - -import android.text.TextUtils; - -import im.vector.matrix.android.api.auth.data.SessionParams; -import im.vector.matrix.android.internal.legacy.RestClient; -import im.vector.matrix.android.internal.legacy.rest.api.EventsApi; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.RestAdapterCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.SimpleApiCallback; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.rest.model.URLPreview; -import im.vector.matrix.android.internal.legacy.rest.model.User; -import im.vector.matrix.android.internal.legacy.rest.model.pid.ThirdPartyProtocol; -import im.vector.matrix.android.internal.legacy.rest.model.publicroom.PublicRoomsFilter; -import im.vector.matrix.android.internal.legacy.rest.model.publicroom.PublicRoomsParams; -import im.vector.matrix.android.internal.legacy.rest.model.publicroom.PublicRoomsResponse; -import im.vector.matrix.android.internal.legacy.rest.model.search.SearchParams; -import im.vector.matrix.android.internal.legacy.rest.model.search.SearchResponse; -import im.vector.matrix.android.internal.legacy.rest.model.search.SearchRoomEventCategoryParams; -import im.vector.matrix.android.internal.legacy.rest.model.search.SearchUsersParams; -import im.vector.matrix.android.internal.legacy.rest.model.search.SearchUsersRequestResponse; -import im.vector.matrix.android.internal.legacy.rest.model.search.SearchUsersResponse; -import im.vector.matrix.android.internal.legacy.rest.model.sync.SyncResponse; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * Class used to make requests to the events API. - */ -public class EventsRestClient extends RestClient { - - private static final int EVENT_STREAM_TIMEOUT_MS = 30000; - - private String mSearchEventsPatternIdentifier = null; - private String mSearchEventsMediaNameIdentifier = null; - private String mSearchUsersPatternIdentifier = null; - - /** - * {@inheritDoc} - */ - public EventsRestClient(SessionParams sessionParams) { - super(sessionParams, EventsApi.class, "", false); - } - - protected EventsRestClient(EventsApi api) { - mApi = api; - } - - /** - * Retrieves the third party server protocols - * - * @param callback the asynchronous callback - */ - public void getThirdPartyServerProtocols(final ApiCallback> callback) { - final String description = "getThirdPartyServerProtocols"; - - mApi.thirdPartyProtocols() - .enqueue(new RestAdapterCallback>(description, mUnsentEventsManager, callback, - new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getThirdPartyServerProtocols(callback); - } - })); - } - - /** - * Get the public rooms count. - * The count can be null. - * - * @param callback the public rooms count callbacks - */ - public void getPublicRoomsCount(final ApiCallback callback) { - getPublicRoomsCount(null, null, false, callback); - } - - /** - * Get the public rooms count. - * The count can be null. - * - * @param server the server url - * @param callback the asynchronous callback - */ - public void getPublicRoomsCount(final String server, final ApiCallback callback) { - getPublicRoomsCount(server, null, false, callback); - } - - /** - * Get the public rooms count. - * The count can be null. - * - * @param server the server url - * @param thirdPartyInstanceId the third party instance id (optional) - * @param includeAllNetworks true to search in all the connected network - * @param callback the asynchronous callback - */ - public void getPublicRoomsCount(final String server, - final String thirdPartyInstanceId, - final boolean includeAllNetworks, - final ApiCallback callback) { - loadPublicRooms(server, thirdPartyInstanceId, includeAllNetworks, null, null, 0, new SimpleApiCallback(callback) { - @Override - public void onSuccess(PublicRoomsResponse publicRoomsResponse) { - callback.onSuccess(publicRoomsResponse.total_room_count_estimate); - } - }); - } - - /** - * Get the list of the public rooms. - * - * @param server search on this home server only (null for any one) - * @param thirdPartyInstanceId the third party instance id (optional) - * @param includeAllNetworks true to search in all the connected network - * @param pattern the pattern to search - * @param since the pagination token - * @param limit the maximum number of public rooms - * @param callback the public rooms callbacks - */ - public void loadPublicRooms(final String server, - final String thirdPartyInstanceId, - final boolean includeAllNetworks, - final String pattern, - final String since, - final int limit, - final ApiCallback callback) { - final String description = "loadPublicRooms"; - - PublicRoomsParams publicRoomsParams = new PublicRoomsParams(); - - publicRoomsParams.thirdPartyInstanceId = thirdPartyInstanceId; - publicRoomsParams.includeAllNetworks = includeAllNetworks; - publicRoomsParams.limit = Math.max(0, limit); - publicRoomsParams.since = since; - - if (!TextUtils.isEmpty(pattern)) { - publicRoomsParams.filter = new PublicRoomsFilter(); - publicRoomsParams.filter.generic_search_term = pattern; - } - - mApi.publicRooms(server, publicRoomsParams) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, - new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - loadPublicRooms(server, thirdPartyInstanceId, includeAllNetworks, pattern, since, limit, callback); - } - })); - } - - - /** - * Synchronise the client's state and receive new messages. Based on server sync C-S v2 API. - *

- * Synchronise the client's state with the latest state on the server. - * Client's use this API when they first log in to get an initial snapshot - * of the state on the server, and then continue to call this API to get - * incremental deltas to the state, and to receive new messages. - * - * @param token the token to stream from (nil in case of initial sync). - * @param serverTimeout the maximum time in ms to wait for an event. - * @param clientTimeout the maximum time in ms the SDK must wait for the server response. - * @param setPresence the optional parameter which controls whether the client is automatically - * marked as online by polling this API. If this parameter is omitted then the client is - * automatically marked as online when it uses this API. Otherwise if - * the parameter is set to "offline" then the client is not marked as - * being online when it uses this API. - * @param filterOrFilterId a JSON filter or the ID of a filter created using the filter API (optional). - * @param callback The request callback - */ - public void syncFromToken(final String token, - final int serverTimeout, - final int clientTimeout, - final String setPresence, - final String filterOrFilterId, - final ApiCallback callback) { - Map params = new HashMap<>(); - int timeout = (EVENT_STREAM_TIMEOUT_MS / 1000); - - if (!TextUtils.isEmpty(token)) { - params.put("since", token); - } - - if (-1 != serverTimeout) { - timeout = serverTimeout; - } - - if (!TextUtils.isEmpty(setPresence)) { - params.put("set_presence", setPresence); - } - - if (!TextUtils.isEmpty(filterOrFilterId)) { - params.put("filter", filterOrFilterId); - } - - params.put("timeout", timeout); - - // increase the timeout because the init sync might require more time to be built - setConnectionTimeout(RestClient.CONNECTION_TIMEOUT_MS * ((null == token) ? 2 : 1)); - - final String description = "syncFromToken"; - // Disable retry because it interferes with clientTimeout - // Let the client manage retries on events streams - mApi.sync(params) - .enqueue(new RestAdapterCallback(description, null, false, callback, - new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - syncFromToken(token, serverTimeout, clientTimeout, setPresence, filterOrFilterId, callback); - } - })); - } - - /** - * Retrieve an event from its event id. - * - * @param eventId the event id - * @param callback the asynchronous callback. - */ - public void getEventFromEventId(final String eventId, final ApiCallback callback) { - final String description = "getEventFromEventId : eventId " + eventId; - - mApi.getEvent(eventId) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getEventFromEventId(eventId, callback); - } - })); - } - - /** - * Search a text in room messages. - * - * @param text the text to search for. - * @param rooms a list of rooms to search in. nil means all rooms the user is in. - * @param beforeLimit the number of events to get before the matching results. - * @param afterLimit the number of events to get after the matching results. - * @param nextBatch the token to pass for doing pagination from a previous response. - * @param callback the request callback - */ - public void searchMessagesByText(final String text, - final List rooms, - final int beforeLimit, - final int afterLimit, - final String nextBatch, - final ApiCallback callback) { - SearchParams searchParams = new SearchParams(); - SearchRoomEventCategoryParams searchEventParams = new SearchRoomEventCategoryParams(); - - searchEventParams.search_term = text; - searchEventParams.order_by = "recent"; - - searchEventParams.event_context = new HashMap<>(); - searchEventParams.event_context.put("before_limit", beforeLimit); - searchEventParams.event_context.put("after_limit", afterLimit); - searchEventParams.event_context.put("include_profile", true); - - if (null != rooms) { - searchEventParams.filter = new HashMap<>(); - searchEventParams.filter.put("rooms", rooms); - } - - searchParams.search_categories = new HashMap<>(); - searchParams.search_categories.put("room_events", searchEventParams); - - final String description = "searchMessageText"; - - final String uid = System.currentTimeMillis() + ""; - mSearchEventsPatternIdentifier = uid + text; - - // don't retry to send the request - // if the search fails, stop it - mApi.searchEvents(searchParams, nextBatch) - .enqueue(new RestAdapterCallback(description, null, new ApiCallback() { - /** - * Tells if the current response for the latest request. - * - * @return true if it is the response of the latest request. - */ - private boolean isActiveRequest() { - return TextUtils.equals(mSearchEventsPatternIdentifier, uid + text); - } - - @Override - public void onSuccess(SearchResponse response) { - if (isActiveRequest()) { - if (null != callback) { - callback.onSuccess(response); - } - - mSearchEventsPatternIdentifier = null; - } - } - - @Override - public void onNetworkError(Exception e) { - if (isActiveRequest()) { - if (null != callback) { - callback.onNetworkError(e); - } - - mSearchEventsPatternIdentifier = null; - } - } - - @Override - public void onMatrixError(MatrixError e) { - if (isActiveRequest()) { - if (null != callback) { - callback.onMatrixError(e); - } - - mSearchEventsPatternIdentifier = null; - } - } - - @Override - public void onUnexpectedError(Exception e) { - if (isActiveRequest()) { - if (null != callback) { - callback.onUnexpectedError(e); - } - - mSearchEventsPatternIdentifier = null; - } - } - - }, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - searchMessagesByText(text, rooms, beforeLimit, afterLimit, nextBatch, callback); - } - })); - } - - /** - * Search a media from its name. - * - * @param name the text to search for. - * @param rooms a list of rooms to search in. nil means all rooms the user is in. - * @param beforeLimit the number of events to get before the matching results. - * @param afterLimit the number of events to get after the matching results. - * @param nextBatch the token to pass for doing pagination from a previous response. - * @param callback the request callback - */ - public void searchMediasByText(final String name, - final List rooms, - final int beforeLimit, - final int afterLimit, - final String nextBatch, - final ApiCallback callback) { - SearchParams searchParams = new SearchParams(); - SearchRoomEventCategoryParams searchEventParams = new SearchRoomEventCategoryParams(); - - searchEventParams.search_term = name; - searchEventParams.order_by = "recent"; - - searchEventParams.event_context = new HashMap<>(); - searchEventParams.event_context.put("before_limit", beforeLimit); - searchEventParams.event_context.put("after_limit", afterLimit); - searchEventParams.event_context.put("include_profile", true); - - searchEventParams.filter = new HashMap<>(); - - if (null != rooms) { - searchEventParams.filter.put("rooms", rooms); - } - - List types = new ArrayList<>(); - types.add(Event.EVENT_TYPE_MESSAGE); - searchEventParams.filter.put("types", types); - - searchEventParams.filter.put("contains_url", true); - - searchParams.search_categories = new HashMap<>(); - searchParams.search_categories.put("room_events", searchEventParams); - - // other unused filter items - // not_types - // not_rooms - // senders - // not_senders - - final String uid = System.currentTimeMillis() + ""; - mSearchEventsMediaNameIdentifier = uid + name; - - final String description = "searchMediasByText"; - - // don't retry to send the request - // if the search fails, stop it - mApi.searchEvents(searchParams, nextBatch) - .enqueue(new RestAdapterCallback(description, null, new ApiCallback() { - /** - * Tells if the current response for the latest request. - * - * @return true if it is the response of the latest request. - */ - private boolean isActiveRequest() { - return TextUtils.equals(mSearchEventsMediaNameIdentifier, uid + name); - } - - @Override - public void onSuccess(SearchResponse newSearchResponse) { - if (isActiveRequest()) { - callback.onSuccess(newSearchResponse); - mSearchEventsMediaNameIdentifier = null; - } - } - - @Override - public void onNetworkError(Exception e) { - if (isActiveRequest()) { - callback.onNetworkError(e); - mSearchEventsMediaNameIdentifier = null; - } - } - - @Override - public void onMatrixError(MatrixError e) { - if (isActiveRequest()) { - callback.onMatrixError(e); - mSearchEventsMediaNameIdentifier = null; - } - } - - @Override - public void onUnexpectedError(Exception e) { - if (isActiveRequest()) { - callback.onUnexpectedError(e); - mSearchEventsMediaNameIdentifier = null; - } - } - - }, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - searchMediasByText(name, rooms, beforeLimit, afterLimit, nextBatch, callback); - } - })); - } - - - /** - * Search users with a patter, - * - * @param text the text to search for. - * @param limit the maximum nbr of users in the response - * @param userIdsFilter the userIds to exclude from the result - * @param callback the request callback - */ - public void searchUsers(final String text, final Integer limit, final Set userIdsFilter, final ApiCallback callback) { - SearchUsersParams searchParams = new SearchUsersParams(); - - searchParams.search_term = text; - searchParams.limit = limit + ((null != userIdsFilter) ? userIdsFilter.size() : 0); - - final String uid = mSearchUsersPatternIdentifier = System.currentTimeMillis() + " " + text + " " + limit; - final String description = "searchUsers"; - - // don't retry to send the request - // if the search fails, stop it - mApi.searchUsers(searchParams) - .enqueue(new RestAdapterCallback(description, null, - new ApiCallback() { - /** - * Tells if the current response for the latest request. - * - * @return true if it is the response of the latest request. - */ - private boolean isActiveRequest() { - return TextUtils.equals(mSearchUsersPatternIdentifier, uid); - } - - @Override - public void onSuccess(SearchUsersRequestResponse aResponse) { - if (isActiveRequest()) { - SearchUsersResponse response = new SearchUsersResponse(); - response.limited = aResponse.limited; - response.results = new ArrayList<>(); - Set filter = (null != userIdsFilter) ? userIdsFilter : new HashSet(); - - if (null != aResponse.results) { - for (SearchUsersRequestResponse.User user : aResponse.results) { - if ((null != user.user_id) && !filter.contains(user.user_id)) { - User addedUser = new User(); - addedUser.user_id = user.user_id; - addedUser.avatar_url = user.avatar_url; - addedUser.displayname = user.display_name; - response.results.add(addedUser); - } - } - } - - callback.onSuccess(response); - mSearchUsersPatternIdentifier = null; - } - } - - @Override - public void onNetworkError(Exception e) { - if (isActiveRequest()) { - callback.onNetworkError(e); - mSearchUsersPatternIdentifier = null; - } - } - - @Override - public void onMatrixError(MatrixError e) { - if (isActiveRequest()) { - callback.onMatrixError(e); - mSearchUsersPatternIdentifier = null; - } - } - - @Override - public void onUnexpectedError(Exception e) { - if (isActiveRequest()) { - callback.onUnexpectedError(e); - mSearchUsersPatternIdentifier = null; - } - } - - }, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - searchUsers(text, limit, userIdsFilter, callback); - } - })); - } - - /** - * Cancel any pending file search request - */ - public void cancelSearchMediasByText() { - mSearchEventsMediaNameIdentifier = null; - } - - /** - * Cancel any pending search request - */ - public void cancelSearchMessagesByText() { - mSearchEventsPatternIdentifier = null; - } - - /** - * Cancel any pending search request - */ - public void cancelUsersSearch() { - mSearchUsersPatternIdentifier = null; - } - - /** - * Retrieve the URL preview information. - * - * @param url the URL - * @param ts the timestamp - * @param callback the asynchronous callback - */ - public void getURLPreview(final String url, final long ts, final ApiCallback callback) { - final String description = "getURLPreview : URL " + url + " with ts " + ts; - - mApi.getURLPreview(url, ts) - .enqueue(new RestAdapterCallback>(description, null, false, - new SimpleApiCallback>(callback) { - @Override - public void onSuccess(Map map) { - if (null != callback) { - callback.onSuccess(new URLPreview(map, url)); - } - } - }, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getURLPreview(url, ts, callback); - } - })); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/FilterRestClient.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/FilterRestClient.java deleted file mode 100644 index 4154cd03..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/FilterRestClient.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2018 Matthias Kesler - * Copyright 2018 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.matrix.android.internal.legacy.rest.client; - -import im.vector.matrix.android.api.auth.data.SessionParams; -import im.vector.matrix.android.internal.legacy.RestClient; -import im.vector.matrix.android.internal.legacy.rest.api.FilterApi; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.RestAdapterCallback; -import im.vector.matrix.android.internal.legacy.rest.model.filter.FilterBody; -import im.vector.matrix.android.internal.legacy.rest.model.filter.FilterResponse; - -public class FilterRestClient extends RestClient { - - /** - * {@inheritDoc} - */ - public FilterRestClient(SessionParams sessionParams) { - super(sessionParams, FilterApi.class, RestClient.URI_API_PREFIX_PATH_R0, false); - } - - /** - * Uploads a FilterBody to homeserver - * - * @param userId the user id - * @param filterBody FilterBody which should be send to server - * @param callback on success callback containing a String with populated filterId - */ - public void uploadFilter(final String userId, final FilterBody filterBody, final ApiCallback callback) { - final String description = "uploadFilter userId : " + userId + " filter : " + filterBody; - - mApi.uploadFilter(userId, filterBody) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - uploadFilter(userId, filterBody, callback); - } - })); - } - - /** - * Get a user's filter by filterId - * - * @param userId the user id - * @param filterId the filter id - * @param callback on success callback containing a User object with populated filterbody - */ - public void getFilter(final String userId, final String filterId, final ApiCallback callback) { - final String description = "getFilter userId : " + userId + " filterId : " + filterId; - - mApi.getFilterById(userId, filterId) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getFilter(userId, filterId, callback); - } - })); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/GroupsRestClient.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/GroupsRestClient.java deleted file mode 100644 index 5be458fc..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/GroupsRestClient.java +++ /dev/null @@ -1,434 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.client; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import im.vector.matrix.android.api.auth.data.SessionParams; -import im.vector.matrix.android.internal.legacy.RestClient; -import im.vector.matrix.android.internal.legacy.rest.api.GroupsApi; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.RestAdapterCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.SimpleApiCallback; -import im.vector.matrix.android.internal.legacy.rest.model.group.AcceptGroupInvitationParams; -import im.vector.matrix.android.internal.legacy.rest.model.group.AddGroupParams; -import im.vector.matrix.android.internal.legacy.rest.model.group.CreateGroupParams; -import im.vector.matrix.android.internal.legacy.rest.model.group.CreateGroupResponse; -import im.vector.matrix.android.internal.legacy.rest.model.group.GetGroupsResponse; -import im.vector.matrix.android.internal.legacy.rest.model.group.GetPublicisedGroupsResponse; -import im.vector.matrix.android.internal.legacy.rest.model.group.GroupInviteUserParams; -import im.vector.matrix.android.internal.legacy.rest.model.group.GroupInviteUserResponse; -import im.vector.matrix.android.internal.legacy.rest.model.group.GroupKickUserParams; -import im.vector.matrix.android.internal.legacy.rest.model.group.GroupProfile; -import im.vector.matrix.android.internal.legacy.rest.model.group.GroupRooms; -import im.vector.matrix.android.internal.legacy.rest.model.group.GroupSummary; -import im.vector.matrix.android.internal.legacy.rest.model.group.GroupUsers; -import im.vector.matrix.android.internal.legacy.rest.model.group.LeaveGroupParams; -import im.vector.matrix.android.internal.legacy.rest.model.group.UpdatePubliciseParams; -import retrofit2.Response; - -/** - * Class used to make requests to the groups API. - */ -public class GroupsRestClient extends RestClient { - - /** - * {@inheritDoc} - */ - public GroupsRestClient(SessionParams sessionParams) { - super(sessionParams, GroupsApi.class, RestClient.URI_API_PREFIX_PATH_R0, false); - } - - protected GroupsRestClient(GroupsApi api) { - mApi = api; - } - - /** - * Create a group. - * - * @param params the room creation parameters - * @param callback the asynchronous callback. - */ - public void createGroup(final CreateGroupParams params, final ApiCallback callback) { - final String description = "createGroup " + params.localpart; - - mApi.createGroup(params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, - new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - createGroup(params, callback); - } - }) { - @Override - public void success(CreateGroupResponse createGroupResponse, Response response) { - onEventSent(); - callback.onSuccess(createGroupResponse.group_id); - } - }); - } - - /** - * Invite an user in a group. - * - * @param groupId the group id - * @param userId the user id - * @param callback the asynchronous callback. - */ - public void inviteUserInGroup(final String groupId, final String userId, final ApiCallback callback) { - final String description = "inviteUserInGroup " + groupId + " - " + userId; - - GroupInviteUserParams params = new GroupInviteUserParams(); - - mApi.inviteUser(groupId, userId, params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, - new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - inviteUserInGroup(groupId, userId, callback); - } - }) { - @Override - public void success(GroupInviteUserResponse groupInviteUserResponse, Response response) { - onEventSent(); - callback.onSuccess(groupInviteUserResponse.state); - } - }); - } - - /** - * Kick an user from a group. - * - * @param groupId the group id - * @param userId the user id - * @param callback the asynchronous callback. - */ - public void KickUserFromGroup(final String groupId, final String userId, final ApiCallback callback) { - final String description = "KickFromGroup " + groupId + " " + userId; - - GroupKickUserParams params = new GroupKickUserParams(); - - mApi.kickUser(groupId, userId, params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - KickUserFromGroup(groupId, userId, callback); - } - })); - } - - /** - * Add a room in a group. - * - * @param groupId the group id - * @param roomId the room id - * @param callback the asynchronous callback. - */ - public void addRoomInGroup(final String groupId, final String roomId, final ApiCallback callback) { - final String description = "addRoomInGroup " + groupId + " " + roomId; - - AddGroupParams params = new AddGroupParams(); - - mApi.addRoom(groupId, roomId, params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - addRoomInGroup(groupId, roomId, callback); - } - })); - } - - /** - * Remove a room from a group. - * - * @param groupId the group id - * @param roomId the room id - * @param callback the asynchronous callback. - */ - public void removeRoomFromGroup(final String groupId, final String roomId, final ApiCallback callback) { - final String description = "removeRoomFromGroup " + groupId + " " + roomId; - - mApi.removeRoom(groupId, roomId) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - removeRoomFromGroup(groupId, roomId, callback); - } - })); - } - - /** - * Update a group profile. - * - * @param groupId the group id - * @param profile the profile - * @param callback the asynchronous callback. - */ - public void updateGroupProfile(final String groupId, final GroupProfile profile, final ApiCallback callback) { - final String description = "updateGroupProfile " + groupId; - - mApi.updateProfile(groupId, profile) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - updateGroupProfile(groupId, profile, callback); - } - })); - } - - /** - * Update a group profile. - * - * @param groupId the group id - * @param callback the asynchronous callback. - */ - public void getGroupProfile(final String groupId, final ApiCallback callback) { - final String description = "getGroupProfile " + groupId; - - mApi.getProfile(groupId) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getGroupProfile(groupId, callback); - } - })); - } - - /** - * Request the group invited users. - * - * @param groupId the group id - * @param callback the asynchronous callback. - */ - public void getGroupInvitedUsers(final String groupId, final ApiCallback callback) { - final String description = "getGroupInvitedUsers " + groupId; - - mApi.getInvitedUsers(groupId) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getGroupInvitedUsers(groupId, callback); - } - })); - } - - /** - * Request the group rooms. - * - * @param groupId the group id - * @param callback the asynchronous callback. - */ - public void getGroupRooms(final String groupId, final ApiCallback callback) { - final String description = "getGroupRooms " + groupId; - - mApi.getRooms(groupId) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getGroupRooms(groupId, callback); - } - })); - } - - /** - * Request the group users. - * - * @param groupId the group id - * @param callback the asynchronous callback. - */ - public void getGroupUsers(final String groupId, final ApiCallback callback) { - final String description = "getGroupUsers " + groupId; - - mApi.getUsers(groupId) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getGroupUsers(groupId, callback); - } - })); - } - - /** - * Request a group summary - * - * @param groupId the group id - * @param callback the asynchronous callback. - */ - public void getGroupSummary(final String groupId, final ApiCallback callback) { - final String description = "getGroupSummary " + groupId; - - mApi.getSummary(groupId) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getGroupSummary(groupId, callback); - } - })); - } - - /** - * Join a group. - * - * @param groupId the group id - * @param callback the asynchronous callback. - */ - public void joinGroup(final String groupId, final ApiCallback callback) { - final String description = "joinGroup " + groupId; - - AcceptGroupInvitationParams params = new AcceptGroupInvitationParams(); - - mApi.acceptInvitation(groupId, params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - joinGroup(groupId, callback); - } - })); - } - - /** - * Leave a group. - * - * @param groupId the group id - * @param callback the asynchronous callback. - */ - public void leaveGroup(final String groupId, final ApiCallback callback) { - final String description = "leaveGroup " + groupId; - - LeaveGroupParams params = new LeaveGroupParams(); - - mApi.leave(groupId, params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - leaveGroup(groupId, callback); - } - })); - } - - /** - * Update a group publicity status. - * - * @param groupId the group id - * @param publicity the new publicity status - * @param callback the asynchronous callback. - */ - public void updateGroupPublicity(final String groupId, final boolean publicity, final ApiCallback callback) { - final String description = "updateGroupPublicity " + groupId + " - " + publicity; - - UpdatePubliciseParams params = new UpdatePubliciseParams(); - params.publicise = publicity; - - mApi.updatePublicity(groupId, params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - updateGroupPublicity(groupId, publicity, callback); - } - })); - } - - /** - * Request the joined groups. - * - * @param callback the asynchronous callback. - */ - public void getJoinedGroups(final ApiCallback> callback) { - final String description = "getJoinedGroups"; - - mApi.getJoinedGroupIds() - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, - new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getJoinedGroups(callback); - } - }) { - @Override - public void success(GetGroupsResponse getGroupsResponse, Response response) { - onEventSent(); - callback.onSuccess(getGroupsResponse.groupIds); - } - }); - } - - /** - * Request the publicised groups for an user. - * - * @param userId the user id - * @param callback the asynchronous callback. - */ - public void getUserPublicisedGroups(final String userId, final ApiCallback> callback) { - getPublicisedGroups(Arrays.asList(userId), new SimpleApiCallback>>(callback) { - @Override - public void onSuccess(Map> map) { - callback.onSuccess(map.get(userId)); - } - }); - } - - /** - * Request the publicised groups for an users list. - * - * @param userIds the user ids list - * @param callback the asynchronous callback - */ - public void getPublicisedGroups(final List userIds, final ApiCallback>> callback) { - final String description = "getPublicisedGroups " + userIds; - - Map> params = new HashMap<>(); - params.put("user_ids", userIds); - - mApi.getPublicisedGroups(params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, - new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getPublicisedGroups(userIds, callback); - } - } - ) { - @Override - public void success(GetPublicisedGroupsResponse getPublicisedGroupsResponse, Response response) { - onEventSent(); - - Map> map = new HashMap<>(); - - for (String userId : userIds) { - List groupIds = null; - - if ((null != getPublicisedGroupsResponse.users) && getPublicisedGroupsResponse.users.containsKey(userId)) { - groupIds = getPublicisedGroupsResponse.users.get(userId); - } - - if (null == groupIds) { - groupIds = new ArrayList<>(); - } - - map.put(userId, groupIds); - } - - callback.onSuccess(map); - } - }); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/LoginRestClient.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/LoginRestClient.java deleted file mode 100644 index 05f1ed41..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/LoginRestClient.java +++ /dev/null @@ -1,359 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.client; - -import android.os.Build; -import android.support.annotation.Nullable; -import android.text.TextUtils; - -import com.google.gson.JsonObject; - -import java.util.List; -import java.util.UUID; - -import im.vector.matrix.android.api.auth.data.Credentials; -import im.vector.matrix.android.api.auth.data.SessionParams; -import im.vector.matrix.android.internal.legacy.RestClient; -import im.vector.matrix.android.internal.legacy.rest.api.LoginApi; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.RestAdapterCallback; -import im.vector.matrix.android.internal.legacy.rest.model.Versions; -import im.vector.matrix.android.internal.legacy.rest.model.login.LoginFlow; -import im.vector.matrix.android.internal.legacy.rest.model.login.LoginFlowResponse; -import im.vector.matrix.android.internal.legacy.rest.model.login.LoginParams; -import im.vector.matrix.android.internal.legacy.rest.model.login.PasswordLoginParams; -import im.vector.matrix.android.internal.legacy.rest.model.login.RegistrationParams; -import im.vector.matrix.android.internal.legacy.rest.model.login.TokenLoginParams; -import retrofit2.Response; - -/** - * Class used to make requests to the login API. - */ -public class LoginRestClient extends RestClient { - - public static final String LOGIN_FLOW_TYPE_PASSWORD = "m.login.password"; - public static final String LOGIN_FLOW_TYPE_OAUTH2 = "m.login.oauth2"; - public static final String LOGIN_FLOW_TYPE_EMAIL_CODE = "m.login.email.code"; - public static final String LOGIN_FLOW_TYPE_EMAIL_URL = "m.login.email.url"; - public static final String LOGIN_FLOW_TYPE_EMAIL_IDENTITY = "m.login.email.identity"; - public static final String LOGIN_FLOW_TYPE_MSISDN = "m.login.msisdn"; - public static final String LOGIN_FLOW_TYPE_RECAPTCHA = "m.login.recaptcha"; - public static final String LOGIN_FLOW_TYPE_DUMMY = "m.login.dummy"; - - /** - * Public constructor. - * - * @param sessionParams the session connection data - */ - public LoginRestClient(SessionParams sessionParams) { - super(sessionParams, LoginApi.class, "", false); - } - - /** - * Get Versions supported by the server and other server capabilities - * - * @param callback the callback - */ - public void getVersions(final ApiCallback callback) { - final String description = "getVersions"; - - mApi.versions() - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, null)); - } - - /** - * Retrieve the login supported flows. - * It should be done to check before displaying a default login form. - * - * @param callback the callback success and failure callback - */ - public void getSupportedLoginFlows(final ApiCallback> callback) { - final String description = "geLoginSupportedFlows"; - - mApi.login() - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, - new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getSupportedLoginFlows(callback); - } - }) { - @Override - public void success(LoginFlowResponse loginFlowResponse, Response response) { - onEventSent(); - callback.onSuccess(loginFlowResponse.flows); - } - }); - } - - /** - * Request an account creation - * - * @param params the registration parameters - * @param callback the callback - */ - public void register(final RegistrationParams params, final ApiCallback callback) { - final String description = "register"; - - // define a default device name only there is a password - if (!TextUtils.isEmpty(params.password) && TextUtils.isEmpty(params.initial_device_display_name)) { - params.initial_device_display_name = Build.MODEL.trim(); - - // Temporary flag to notify the server that we support msisdn flow. Used to prevent old app - // versions to end up in fallback because the HS returns the msisdn flow which they don't support - // Only send it if we send any params at all (the password param is - // mandatory, so if we send any params, we'll send the password param) - params.x_show_msisdn = true; - } else if (params.password == null && params.username == null && params.auth == null) { - // Happens when we call the method to get flows, also add flag in that case - params.x_show_msisdn = true; - } - - mApi.register(params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - register(params, callback); - } - }) { - - @Override - public void success(JsonObject jsonObject, Response response) { - onEventSent(); - mCredentials = gson.fromJson(jsonObject, Credentials.class); - callback.onSuccess(mCredentials); - } - }); - } - - /** - * Attempt to login with username/password - * - * @param user the username - * @param password the password - * @param callback the callback success and failure callback - */ - public void loginWithUser(final String user, final String password, final ApiCallback callback) { - loginWithUser(user, password, null, null, callback); - } - - /** - * Attempt to login with username/password - * - * @param user the username - * @param password the password - * @param deviceName the device name - * @param deviceId the device id, used for e2e encryption - * @param callback the callback success and failure callback - */ - public void loginWithUser(final String user, - final String password, - final String deviceName, - @Nullable final String deviceId, - final ApiCallback callback) { - final String description = "loginWithUser : " + user; - - PasswordLoginParams params = new PasswordLoginParams(); - params.setUserIdentifier(user, password); - params.setDeviceName(deviceName); - params.setDeviceId(deviceId); - - login(params, callback, description); - } - - /** - * Attempt to login with 3pid/password - * - * @param medium the medium of the 3pid - * @param address the address of the 3pid - * @param password the password - * @param callback the callback success and failure callback - */ - public void loginWith3Pid(final String medium, final String address, final String password, final ApiCallback callback) { - loginWith3Pid(medium, address, password, null, null, callback); - } - - /** - * Attempt to login with 3pid/password - * - * @param medium the medium of the 3pid - * @param address the address of the 3pid - * @param password the password - * @param deviceName the device name - * @param deviceId the device id, used for e2e encryption - * @param callback the callback success and failure callback - */ - public void loginWith3Pid(final String medium, - final String address, - final String password, - final String deviceName, - @Nullable final String deviceId, - final ApiCallback callback) { - final String description = "loginWith3pid : " + address; - - PasswordLoginParams params = new PasswordLoginParams(); - params.setThirdPartyIdentifier(medium, address, password); - params.setDeviceName(deviceName); - params.setDeviceId(deviceId); - - login(params, callback, description); - } - - /** - * Attempt to login with phone number/password - * - * @param phoneNumber the phone number - * @param countryCode the ISO country code - * @param password the password - * @param callback the callback success and failure callback - */ - public void loginWithPhoneNumber(final String phoneNumber, final String countryCode, final String password, final ApiCallback callback) { - loginWithPhoneNumber(phoneNumber, countryCode, password, null, null, callback); - } - - /** - * Attempt to login with phone number/password - * - * @param phoneNumber the phone number - * @param countryCode the ISO country code - * @param password the password - * @param deviceName the device name - * @param deviceId the device id, used for e2e encryption - * @param callback the callback success and failure callback - */ - public void loginWithPhoneNumber(final String phoneNumber, - final String countryCode, - final String password, - final String deviceName, - @Nullable final String deviceId, - final ApiCallback callback) { - final String description = "loginWithPhoneNumber : " + phoneNumber; - - PasswordLoginParams params = new PasswordLoginParams(); - params.setPhoneIdentifier(phoneNumber, countryCode, password); - params.setDeviceName(deviceName); - params.setDeviceId(deviceId); - - login(params, callback, description); - } - - /** - * Make a login request. - * - * @param params custom login params - * @param callback the asynchronous callback - */ - public void login(LoginParams params, final ApiCallback callback) { - login(params, callback, "login with a " + params.getClass().getSimpleName() + " object"); - } - - /** - * Make login request - * - * @param params login params - * @param callback the asynchronous callback - * @param description the request description - */ - private void login(final LoginParams params, final ApiCallback callback, final String description) { - mApi.login(params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - login(params, callback, description); - } - }) { - @Override - public void success(JsonObject jsonObject, Response response) { - onEventSent(); - mCredentials = gson.fromJson(jsonObject, Credentials.class); - callback.onSuccess(mCredentials); - } - }); - } - - /** - * Attempt a user/token log in. - * - * @param user the user name - * @param token the token - * @param deviceName the device name - * @param callback the callback success and failure callback - */ - public void loginWithToken(final String user, final String token, final String deviceName, final ApiCallback callback) { - loginWithToken(user, token, UUID.randomUUID().toString(), deviceName, callback); - } - - /** - * Attempt a user/token log in. - * - * @param user the user name - * @param token the token - * @param txn_id the client transaction id to include in the request - * @param deviceName the device name - * @param callback the callback success and failure callback - */ - public void loginWithToken(final String user, final String token, final String txn_id, String deviceName, final ApiCallback callback) { - // privacy - //final String description = "loginWithPassword user : " + user; - final String description = "loginWithPassword user"; - - TokenLoginParams params = new TokenLoginParams(); - params.user = user; - params.token = token; - params.txn_id = txn_id; - - if ((null != deviceName) && !TextUtils.isEmpty(deviceName.trim())) { - params.initial_device_display_name = deviceName.trim(); - } else { - params.initial_device_display_name = Build.MODEL.trim(); - } - - mApi.login(params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - loginWithToken(user, token, txn_id, callback); - } - }) { - @Override - public void success(JsonObject jsonObject, Response response) { - onEventSent(); - mCredentials = gson.fromJson(jsonObject, Credentials.class); - callback.onSuccess(mCredentials); - } - }); - } - - /** - * Invalidate the access token, so that it can no longer be used for authorization. - * - * @param callback the callback success and failure callback - */ - public void logout(final ApiCallback callback) { - // privacy - final String description = "logout user"; - - mApi.logout() - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - logout(callback); - } - })); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/MXRestExecutorService.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/MXRestExecutorService.java deleted file mode 100644 index fd9692b1..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/MXRestExecutorService.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.rest.client; - -import android.os.HandlerThread; -import android.support.annotation.NonNull; - -import im.vector.matrix.android.internal.legacy.util.MXOsHandler; - -import java.util.Collections; -import java.util.List; -import java.util.concurrent.AbstractExecutorService; -import java.util.concurrent.TimeUnit; - -/** - * MXRestExecutor is a basic thread executor - */ -public class MXRestExecutorService extends AbstractExecutorService { - private HandlerThread mHandlerThread; - private MXOsHandler mHandler; - - public MXRestExecutorService() { - mHandlerThread = new HandlerThread("MXRestExecutor" + hashCode(), Thread.MIN_PRIORITY); - mHandlerThread.start(); - mHandler = new MXOsHandler(mHandlerThread.getLooper()); - } - - @Override - public void execute(final Runnable r) { - mHandler.post(r); - } - - /** - * Stop any running thread - */ - public void stop() { - if (null != mHandlerThread) { - mHandlerThread.quit(); - } - } - - @Override public void shutdown() { - - } - - @NonNull @Override public List shutdownNow() { - return Collections.emptyList(); - } - - @Override public boolean isShutdown() { - return false; - } - - @Override public boolean isTerminated() { - return false; - } - - @Override - public boolean awaitTermination(long timeout, @NonNull TimeUnit unit) throws InterruptedException { - return false; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/MediaScanRestClient.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/MediaScanRestClient.java deleted file mode 100644 index b1acd4ee..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/MediaScanRestClient.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.rest.client; - -import android.support.annotation.Nullable; -import android.text.TextUtils; - -import org.matrix.olm.OlmException; -import org.matrix.olm.OlmPkEncryption; -import org.matrix.olm.OlmPkMessage; - -import im.vector.matrix.android.api.auth.data.SessionParams; -import im.vector.matrix.android.internal.legacy.RestClient; -import im.vector.matrix.android.internal.legacy.data.store.IMXStore; -import im.vector.matrix.android.internal.legacy.rest.api.MediaScanApi; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.DefaultRetrofit2CallbackWrapper; -import im.vector.matrix.android.internal.legacy.rest.callback.SimpleApiCallback; -import im.vector.matrix.android.internal.legacy.rest.model.EncryptedMediaScanBody; -import im.vector.matrix.android.internal.legacy.rest.model.EncryptedMediaScanEncryptedBody; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.rest.model.MediaScanPublicKeyResult; -import im.vector.matrix.android.internal.legacy.rest.model.MediaScanResult; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.EncryptedBodyFileInfo; -import im.vector.matrix.android.internal.legacy.util.JsonUtils; -import retrofit2.Call; - -/** - * Class used to make requests to the anti-virus scanner API. - */ -public class MediaScanRestClient extends RestClient { - - @Nullable - private IMXStore mMxStore; - - /** - * {@inheritDoc} - */ - public MediaScanRestClient(SessionParams sessionParams) { - super(sessionParams, MediaScanApi.class, RestClient.URI_API_PREFIX_PATH_MEDIA_PROXY_UNSTABLE, false, EndPointServer.ANTIVIRUS_SERVER); - } - - /** - * Set MxStore instance - * - * @param mxStore - */ - public void setMxStore(IMXStore mxStore) { - mMxStore = mxStore; - } - - /** - * Get the current public curve25519 key that the AV server is advertising. - * Read the value from cache if any - * - * @param callback on success callback containing the server public key - */ - public void getServerPublicKey(final ApiCallback callback) { - if (mMxStore == null) { - callback.onUnexpectedError(new Exception("MxStore not configured")); - return; - } - - // Check in cache - String keyFromCache = mMxStore.getAntivirusServerPublicKey(); - if (keyFromCache != null) { - callback.onSuccess(keyFromCache); - } else { - mApi.getServerPublicKey().enqueue(new DefaultRetrofit2CallbackWrapper<>(new SimpleApiCallback(callback) { - @Override - public void onSuccess(MediaScanPublicKeyResult info) { - // Store the key in cache for next times - mMxStore.setAntivirusServerPublicKey(info.mCurve25519PublicKey); - - // Note: for some reason info.mCurve25519PublicKey may be null - if (info.mCurve25519PublicKey != null) { - callback.onSuccess(info.mCurve25519PublicKey); - } else { - callback.onUnexpectedError(new Exception("Unable to get server public key from Json")); - } - } - - @Override - public void onMatrixError(MatrixError e) { - // Old Antivirus scanner instance will return a 404 - if (e.mStatus == 404) { - // On 404 consider the public key is not available, so do not encrypt body - mMxStore.setAntivirusServerPublicKey(""); - - callback.onSuccess(""); - } else { - super.onMatrixError(e); - } - } - })); - } - } - - /** - * Reset Antivirus server public key on cache - */ - public void resetServerPublicKey() { - if (mMxStore != null) { - mMxStore.setAntivirusServerPublicKey(null); - } - } - - /** - * Scan an unencrypted file. - * - * @param domain the server name extracted from the matrix content uri - * @param mediaId the media id extracted from the matrix content uri - * @param callback on success callback containing a MediaScanResult object - */ - public void scanUnencryptedFile(final String domain, final String mediaId, final ApiCallback callback) { - mApi.scanUnencrypted(domain, mediaId).enqueue(new DefaultRetrofit2CallbackWrapper<>(callback)); - } - - /** - * Scan an encrypted file. - * - * @param encryptedMediaScanBody the encryption information required to decrypt the content before scanning it. - * @param callback on success callback containing a MediaScanResult object - */ - public void scanEncryptedFile(final EncryptedMediaScanBody encryptedMediaScanBody, final ApiCallback callback) { - // Encrypt encryptedMediaScanBody if the server support it - getServerPublicKey(new SimpleApiCallback(callback) { - @Override - public void onSuccess(String serverPublicKey) { - Call request; - - // Encrypt the data, if antivirus server supports it - if (!TextUtils.isEmpty(serverPublicKey)) { - try { - OlmPkEncryption olmPkEncryption = new OlmPkEncryption(); - olmPkEncryption.setRecipientKey(serverPublicKey); - - String data = JsonUtils.getCanonicalizedJsonString(encryptedMediaScanBody); - - OlmPkMessage message = olmPkEncryption.encrypt(data); - - EncryptedMediaScanEncryptedBody encryptedMediaScanEncryptedBody = new EncryptedMediaScanEncryptedBody(); - encryptedMediaScanEncryptedBody.encryptedBodyFileInfo = new EncryptedBodyFileInfo(message); - - request = mApi.scanEncrypted(encryptedMediaScanEncryptedBody); - } catch (OlmException e) { - // should not happen. Send the error to the caller - request = null; - callback.onUnexpectedError(e); - } - } else { - // No public key on this server, do not encrypt data - request = mApi.scanEncrypted(encryptedMediaScanBody); - } - - if (request != null) { - request.enqueue(new DefaultRetrofit2CallbackWrapper<>(callback)); - } - } - }); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/PresenceRestClient.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/PresenceRestClient.java deleted file mode 100644 index c5cd1e4b..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/PresenceRestClient.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.client; - -import im.vector.matrix.android.api.auth.data.SessionParams; -import im.vector.matrix.android.internal.legacy.RestClient; -import im.vector.matrix.android.internal.legacy.rest.api.PresenceApi; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.RestAdapterCallback; -import im.vector.matrix.android.internal.legacy.rest.model.User; - -/** - * Class used to make requests to the presence API. - */ -public class PresenceRestClient extends RestClient { - - /** - * {@inheritDoc} - */ - public PresenceRestClient(SessionParams sessionParams) { - super(sessionParams, PresenceApi.class, RestClient.URI_API_PREFIX_PATH_R0, false); - } - - /** - * Get a user's presence state. - * - * @param userId the user id - * @param callback on success callback containing a User object with populated presence and statusMsg fields - */ - public void getPresence(final String userId, final ApiCallback callback) { - final String description = "getPresence userId : " + userId; - - mApi.presenceStatus(userId) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getPresence(userId, callback); - } - })); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/ProfileRestClient.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/ProfileRestClient.java deleted file mode 100644 index d3ebfb38..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/ProfileRestClient.java +++ /dev/null @@ -1,466 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.client; - -import android.text.TextUtils; - -import java.util.List; -import java.util.Map; - -import im.vector.matrix.android.api.auth.data.SessionParams; -import im.vector.matrix.android.internal.legacy.RestClient; -import im.vector.matrix.android.internal.legacy.rest.api.ProfileApi; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.RestAdapterCallback; -import im.vector.matrix.android.internal.legacy.rest.model.AuthParams; -import im.vector.matrix.android.internal.legacy.rest.model.ChangePasswordParams; -import im.vector.matrix.android.internal.legacy.rest.model.DeactivateAccountParams; -import im.vector.matrix.android.internal.legacy.rest.model.ForgetPasswordParams; -import im.vector.matrix.android.internal.legacy.rest.model.ForgetPasswordResponse; -import im.vector.matrix.android.internal.legacy.rest.model.RequestEmailValidationParams; -import im.vector.matrix.android.internal.legacy.rest.model.RequestEmailValidationResponse; -import im.vector.matrix.android.internal.legacy.rest.model.RequestPhoneNumberValidationParams; -import im.vector.matrix.android.internal.legacy.rest.model.RequestPhoneNumberValidationResponse; -import im.vector.matrix.android.internal.legacy.rest.model.ThreePidCreds; -import im.vector.matrix.android.internal.legacy.rest.model.User; -import im.vector.matrix.android.internal.legacy.rest.model.pid.AccountThreePidsResponse; -import im.vector.matrix.android.internal.legacy.rest.model.pid.AddThreePidsParams; -import im.vector.matrix.android.internal.legacy.rest.model.pid.DeleteThreePidParams; -import im.vector.matrix.android.internal.legacy.rest.model.pid.ThirdPartyIdentifier; -import im.vector.matrix.android.internal.legacy.rest.model.pid.ThreePid; -import retrofit2.Response; - -/** - * Class used to make requests to the profile API. - */ -public class ProfileRestClient extends RestClient { - private static final String LOG_TAG = ProfileRestClient.class.getSimpleName(); - - /** - * {@inheritDoc} - */ - public ProfileRestClient(SessionParams sessionParams) { - super(sessionParams, ProfileApi.class, "", false); - } - - /** - * Get the user's display name. - * - * @param userId the user id - * @param callback the callback to return the name on success - */ - public void displayname(final String userId, final ApiCallback callback) { - final String description = "display name userId : " + userId; - - mApi.displayname(userId) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - displayname(userId, callback); - } - }) { - @Override - public void success(User user, Response response) { - onEventSent(); - callback.onSuccess(user.displayname); - } - }); - } - - /** - * Update this user's own display name. - * - * @param newName the new name - * @param callback the callback if the call succeeds - */ - public void updateDisplayname(final String newName, final ApiCallback callback) { - // privacy - //final String description = "updateDisplayname newName : " + newName; - final String description = "update display name"; - - // TODO Do not create a User for this - User user = new User(); - user.displayname = newName; - - // don't retry if the network comes back - // let the user chooses what he want to do - mApi.displayname(mCredentials.getUserId(), user) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - updateDisplayname(newName, callback); - } - })); - } - - /** - * Get the user's avatar URL. - * - * @param userId the user id - * @param callback the callback to return the URL on success - */ - public void avatarUrl(final String userId, final ApiCallback callback) { - final String description = "avatarUrl userId : " + userId; - - mApi.avatarUrl(userId) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - avatarUrl(userId, callback); - } - }) { - @Override - public void success(User user, Response response) { - onEventSent(); - callback.onSuccess(user.getAvatarUrl()); - } - }); - } - - /** - * Update this user's own avatar URL. - * - * @param newUrl the new name - * @param callback the callback if the call succeeds - */ - public void updateAvatarUrl(final String newUrl, final ApiCallback callback) { - // privacy - //final String description = "updateAvatarUrl newUrl : " + newUrl; - final String description = "updateAvatarUrl"; - - // TODO Do not create a User for this - User user = new User(); - user.setAvatarUrl(newUrl); - - mApi.avatarUrl(mCredentials.getUserId(), user) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - updateAvatarUrl(newUrl, callback); - } - })); - } - - /** - * Update the password - * - * @param userId the user id - * @param oldPassword the former password - * @param newPassword the new password - * @param callback the callback - */ - public void updatePassword(final String userId, final String oldPassword, final String newPassword, final ApiCallback callback) { - // privacy - //final String description = "update password : " + userId + " oldPassword " + oldPassword + " newPassword " + newPassword; - final String description = "update password"; - - ChangePasswordParams passwordParams = new ChangePasswordParams(); - - passwordParams.auth = new AuthParams(); - passwordParams.auth.type = LoginRestClient.LOGIN_FLOW_TYPE_PASSWORD; - passwordParams.auth.user = userId; - passwordParams.auth.password = oldPassword; - passwordParams.new_password = newPassword; - - mApi.updatePassword(passwordParams) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - updatePassword(userId, oldPassword, newPassword, callback); - } - } - )); - } - - /** - * Reset the password to a new one. - * - * @param newPassword the new password - * @param threepid_creds the three pids. - * @param callback the callback - */ - public void resetPassword(final String newPassword, final Map threepid_creds, final ApiCallback callback) { - // privacy - //final String description = "Reset password : " + threepid_creds + " newPassword " + newPassword; - final String description = "Reset password"; - - ChangePasswordParams passwordParams = new ChangePasswordParams(); - - passwordParams.auth = new AuthParams(); - passwordParams.auth.type = "m.login.email.identity"; - passwordParams.auth.threepid_creds = threepid_creds; - passwordParams.new_password = newPassword; - - mApi.updatePassword(passwordParams) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - resetPassword(newPassword, threepid_creds, callback); - } - })); - } - - /** - * Reset the password server side. - * - * @param email the email to send the password reset. - * @param callback the callback - */ - public void forgetPassword(final String email, final ApiCallback callback) { - final String description = "forget password"; - - if (!TextUtils.isEmpty(email)) { - final ThreePid pid = new ThreePid(email, ThreePid.MEDIUM_EMAIL); - - final ForgetPasswordParams forgetPasswordParams = new ForgetPasswordParams(); - forgetPasswordParams.email = email; - forgetPasswordParams.client_secret = pid.clientSecret; - forgetPasswordParams.send_attempt = 1; - forgetPasswordParams.id_server = mHsConfig.getIdentityServerUri().getHost(); - - mApi.forgetPassword(forgetPasswordParams) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, - new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - forgetPassword(email, callback); - } - }) { - @Override - public void success(ForgetPasswordResponse forgetPasswordResponse, Response response) { - onEventSent(); - - pid.sid = forgetPasswordResponse.sid; - callback.onSuccess(pid); - } - }); - } - } - - /** - * Deactivate account - * - * @param type type of authentication - * @param userId current user id - * @param userPassword current password - * @param eraseUserData true to also erase all the user data - * @param callback the callback - */ - public void deactivateAccount(final String type, - final String userId, - final String userPassword, - final boolean eraseUserData, - final ApiCallback callback) { - final String description = "deactivate account"; - - final DeactivateAccountParams params = new DeactivateAccountParams(); - params.auth = new AuthParams(); - params.auth.type = type; - params.auth.user = userId; - params.auth.password = userPassword; - - params.erase = eraseUserData; - - mApi.deactivate(params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - deactivateAccount(type, userId, userPassword, eraseUserData, callback); - } - })); - } - - /** - * List all 3PIDs linked to the Matrix user account. - * - * @param callback the asynchronous callback called with the response - */ - public void threePIDs(final ApiCallback> callback) { - final String description = "threePIDs"; - - mApi.threePIDs() - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, null) { - @Override - public void success(AccountThreePidsResponse accountThreePidsResponse, Response response) { - onEventSent(); - if (null != callback) { - callback.onSuccess(accountThreePidsResponse.threepids); - } - - } - }); - } - - /** - * Request an email validation token. - * - * @param address the email address - * @param clientSecret the client secret number - * @param attempt the attempt count - * @param nextLink the next link - * @param isDuringRegistration true if it occurs during a registration flow - * @param callback the callback - */ - public void requestEmailValidationToken(final String address, final String clientSecret, final int attempt, - final String nextLink, final boolean isDuringRegistration, - final ApiCallback callback) { - final String description = "requestEmailValidationToken"; - - RequestEmailValidationParams params = new RequestEmailValidationParams(); - params.email = address; - params.clientSecret = clientSecret; - params.sendAttempt = attempt; - params.id_server = mHsConfig.getIdentityServerUri().getHost(); - if (!TextUtils.isEmpty(nextLink)) { - params.next_link = nextLink; - } - - final RestAdapterCallback adapterCallback - = new RestAdapterCallback(description, mUnsentEventsManager, callback, - new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - requestEmailValidationToken(address, clientSecret, attempt, nextLink, isDuringRegistration, callback); - } - } - ) { - @Override - public void success(RequestEmailValidationResponse requestEmailValidationResponse, Response response) { - onEventSent(); - requestEmailValidationResponse.email = address; - requestEmailValidationResponse.clientSecret = clientSecret; - requestEmailValidationResponse.sendAttempt = attempt; - - callback.onSuccess(requestEmailValidationResponse); - } - }; - - if (isDuringRegistration) { - // URL differs in that case - mApi.requestEmailValidationForRegistration(params).enqueue(adapterCallback); - } else { - mApi.requestEmailValidation(params).enqueue(adapterCallback); - } - } - - /** - * Request a phone number validation token. - * - * @param phoneNumber the phone number - * @param countryCode the country code of the phone number - * @param clientSecret the client secret number - * @param attempt the attempt count - * @param isDuringRegistration true if it occurs during a registration flow - * @param callback the callback - */ - public void requestPhoneNumberValidationToken(final String phoneNumber, final String countryCode, - final String clientSecret, final int attempt, - final boolean isDuringRegistration, final ApiCallback callback) { - final String description = "requestPhoneNumberValidationToken"; - - RequestPhoneNumberValidationParams params = new RequestPhoneNumberValidationParams(); - params.phone_number = phoneNumber; - params.country = countryCode; - params.clientSecret = clientSecret; - params.sendAttempt = attempt; - params.id_server = mHsConfig.getIdentityServerUri().getHost(); - - final RestAdapterCallback adapterCallback - = new RestAdapterCallback(description, mUnsentEventsManager, callback, - new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - requestPhoneNumberValidationToken(phoneNumber, countryCode, clientSecret, attempt, isDuringRegistration, callback); - } - } - ) { - @Override - public void success(RequestPhoneNumberValidationResponse requestPhoneNumberValidationResponse, Response response) { - onEventSent(); - requestPhoneNumberValidationResponse.clientSecret = clientSecret; - requestPhoneNumberValidationResponse.sendAttempt = attempt; - - callback.onSuccess(requestPhoneNumberValidationResponse); - } - }; - - if (isDuringRegistration) { - // URL differs in that case - mApi.requestPhoneNumberValidationForRegistration(params).enqueue(adapterCallback); - } else { - mApi.requestPhoneNumberValidation(params).enqueue(adapterCallback); - } - } - - /** - * Add an 3Pids to an user - * - * @param pid the 3Pid to add - * @param bind bind the email - * @param callback the asynchronous callback called with the response - */ - public void add3PID(final ThreePid pid, final boolean bind, final ApiCallback callback) { - final String description = "add3PID"; - - AddThreePidsParams params = new AddThreePidsParams(); - params.three_pid_creds = new ThreePidCreds(); - String identityServerHost = mHsConfig.getIdentityServerUri().toString(); - if (identityServerHost != null) { - if (identityServerHost.startsWith("http://")) { - identityServerHost = identityServerHost.substring("http://".length()); - } else if (identityServerHost.startsWith("https://")) { - identityServerHost = identityServerHost.substring("https://".length()); - } - } - params.three_pid_creds.id_server = identityServerHost; - params.three_pid_creds.sid = pid.sid; - params.three_pid_creds.client_secret = pid.clientSecret; - - params.bind = bind; - - mApi.add3PID(params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - add3PID(pid, bind, callback); - } - })); - } - - /** - * Delete a 3pid of the user - * - * @param pid the 3Pid to delete - * @param callback the asynchronous callback called with the response - */ - public void delete3PID(final ThirdPartyIdentifier pid, final ApiCallback callback) { - final String description = "delete3PID"; - - final DeleteThreePidParams params = new DeleteThreePidParams(); - params.medium = pid.medium; - params.address = pid.address; - - mApi.delete3PID(params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - delete3PID(pid, callback); - } - }) - ); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/PushRulesRestClient.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/PushRulesRestClient.java deleted file mode 100644 index 85a73ea3..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/PushRulesRestClient.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.client; - -import im.vector.matrix.android.api.auth.data.SessionParams; -import im.vector.matrix.android.internal.legacy.RestClient; -import im.vector.matrix.android.internal.legacy.rest.api.PushRulesApi; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.DefaultRetrofit2CallbackWrapper; -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.BingRule; -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.PushRulesResponse; - -public class PushRulesRestClient extends RestClient { - - /** - * {@inheritDoc} - */ - public PushRulesRestClient(SessionParams sessionParams) { - super(sessionParams, PushRulesApi.class, RestClient.URI_API_PREFIX_PATH_R0, false); - } - - /** - * Retrieve the push rules list. - * - * @param callback the asynchronous callback. - */ - public void getAllRules(final ApiCallback callback) { - mApi.getAllRules().enqueue(new DefaultRetrofit2CallbackWrapper<>(callback)); - } - - /** - * Update the rule enable status. - * - * @param Kind the rule kind - * @param ruleId the rule id - * @param status the rule state - * @param callback the asynchronous callback. - */ - public void updateEnableRuleStatus(String Kind, String ruleId, boolean status, final ApiCallback callback) { - mApi.updateEnableRuleStatus(Kind, ruleId, status).enqueue(new DefaultRetrofit2CallbackWrapper<>(callback)); - } - - /** - * Update the rule actions lists. - * - * @param Kind the rule kind - * @param ruleId the rule id - * @param actions the rule actions list - * @param callback the asynchronous callback - */ - public void updateRuleActions(String Kind, String ruleId, Object actions, final ApiCallback callback) { - mApi.updateRuleActions(Kind, ruleId, actions).enqueue(new DefaultRetrofit2CallbackWrapper<>(callback)); - } - - /** - * Delete a rule. - * - * @param Kind the rule kind - * @param ruleId the rule id - * @param callback the asynchronous callback - */ - public void deleteRule(String Kind, String ruleId, final ApiCallback callback) { - mApi.deleteRule(Kind, ruleId).enqueue(new DefaultRetrofit2CallbackWrapper<>(callback)); - } - - /** - * Add a rule. - * - * @param rule the rule - * @param callback the asynchronous callback - */ - public void addRule(BingRule rule, final ApiCallback callback) { - mApi.addRule(rule.kind, rule.ruleId, rule.toJsonElement()).enqueue(new DefaultRetrofit2CallbackWrapper<>(callback)); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/PushersRestClient.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/PushersRestClient.java deleted file mode 100644 index 5bfb2485..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/PushersRestClient.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright 2015 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.client; - -import java.util.HashMap; - -import im.vector.matrix.android.api.auth.data.SessionParams; -import im.vector.matrix.android.internal.legacy.RestClient; -import im.vector.matrix.android.internal.legacy.data.Pusher; -import im.vector.matrix.android.internal.legacy.rest.api.PushersApi; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.RestAdapterCallback; -import im.vector.matrix.android.internal.legacy.rest.model.PushersResponse; - -/** - * REST client for the Pushers API. - */ -public class PushersRestClient extends RestClient { - private static final String LOG_TAG = PushersRestClient.class.getSimpleName(); - - private static final String PUSHER_KIND_HTTP = "http"; - private static final String DATA_KEY_HTTP_URL = "url"; - - public PushersRestClient(SessionParams sessionParams) { - super(sessionParams, PushersApi.class, RestClient.URI_API_PREFIX_PATH_R0, true); - } - - /** - * Add a new HTTP pusher. - * - * @param pushkey the pushkey - * @param appId the application id - * @param profileTag the profile tag - * @param lang the language - * @param appDisplayName a human-readable application name - * @param deviceDisplayName a human-readable device name - * @param url the URL that should be used to send notifications - * @param append append the pusher - * @param withEventIdOnly true to limit the push content - * @param callback the asynchronous callback - */ - public void addHttpPusher(final String pushkey, - final String appId, - final String profileTag, - final String lang, - final String appDisplayName, - final String deviceDisplayName, - final String url, - boolean append, - boolean withEventIdOnly, - final ApiCallback callback) { - manageHttpPusher(pushkey, appId, profileTag, lang, appDisplayName, deviceDisplayName, url, append, withEventIdOnly, true, callback); - } - - /** - * remove a new HTTP pusher. - * - * @param pushkey the pushkey - * @param appId the application id - * @param profileTag the profile tag - * @param lang the language - * @param appDisplayName a human-readable application name - * @param deviceDisplayName a human-readable device name - * @param url the URL that should be used to send notifications - * @param callback the asynchronous callback - */ - public void removeHttpPusher(final String pushkey, - final String appId, - final String profileTag, - final String lang, - final String appDisplayName, - final String deviceDisplayName, - final String url, - final ApiCallback callback) { - manageHttpPusher(pushkey, appId, profileTag, lang, appDisplayName, deviceDisplayName, url, false, false, false, callback); - } - - - /** - * add/remove a new HTTP pusher. - * - * @param pushkey the pushkey - * @param appId the application id - * @param profileTag the profile tag - * @param lang the language - * @param appDisplayName a human-readable application name - * @param deviceDisplayName a human-readable device name - * @param url the URL that should be used to send notifications - * @param withEventIdOnly true to limit the push content - * @param addPusher true to add the pusher / false to remove it - * @param callback the asynchronous callback - */ - private void manageHttpPusher(final String pushkey, - final String appId, - final String profileTag, - final String lang, - final String appDisplayName, - final String deviceDisplayName, - final String url, - final boolean append, - final boolean withEventIdOnly, - final boolean addPusher, - final ApiCallback callback) { - Pusher pusher = new Pusher(); - pusher.pushkey = pushkey; - pusher.appId = appId; - pusher.profileTag = profileTag; - pusher.lang = lang; - pusher.kind = addPusher ? PUSHER_KIND_HTTP : null; - pusher.appDisplayName = appDisplayName; - pusher.deviceDisplayName = deviceDisplayName; - pusher.data = new HashMap<>(); - pusher.data.put(DATA_KEY_HTTP_URL, url); - - if (addPusher) { - pusher.append = append; - } - - if (withEventIdOnly) { - pusher.data.put("format", "event_id_only"); - } - - final String description = "manageHttpPusher"; - - mApi.set(pusher) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - manageHttpPusher(pushkey, appId, profileTag, lang, appDisplayName, deviceDisplayName, - url, append, withEventIdOnly, addPusher, callback); - } - })); - } - - /** - * Retrieve the pushers list - * - * @param callback the callback - */ - public void getPushers(final ApiCallback callback) { - final String description = "getPushers"; - - mApi.get() - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getPushers(callback); - } - })); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/RoomsRestClient.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/RoomsRestClient.java deleted file mode 100644 index da95b19b..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/RoomsRestClient.java +++ /dev/null @@ -1,1022 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.client; - -import android.support.annotation.Nullable; -import android.text.TextUtils; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; - -import java.util.HashMap; -import java.util.Map; - -import im.vector.matrix.android.api.auth.data.SessionParams; -import im.vector.matrix.android.internal.legacy.RestClient; -import im.vector.matrix.android.internal.legacy.data.RoomState; -import im.vector.matrix.android.internal.legacy.data.timeline.EventTimeline; -import im.vector.matrix.android.internal.legacy.rest.api.RoomsApi; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.RestAdapterCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.SimpleApiCallback; -import im.vector.matrix.android.internal.legacy.rest.model.BannedUser; -import im.vector.matrix.android.internal.legacy.rest.model.ChunkEvents; -import im.vector.matrix.android.internal.legacy.rest.model.CreateRoomParams; -import im.vector.matrix.android.internal.legacy.rest.model.CreateRoomResponse; -import im.vector.matrix.android.internal.legacy.rest.model.CreatedEvent; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.EventContext; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.rest.model.PowerLevels; -import im.vector.matrix.android.internal.legacy.rest.model.ReportContentParams; -import im.vector.matrix.android.internal.legacy.rest.model.RoomAliasDescription; -import im.vector.matrix.android.internal.legacy.rest.model.RoomDirectoryVisibility; -import im.vector.matrix.android.internal.legacy.rest.model.RoomMember; -import im.vector.matrix.android.internal.legacy.rest.model.TokensChunkEvents; -import im.vector.matrix.android.internal.legacy.rest.model.Typing; -import im.vector.matrix.android.internal.legacy.rest.model.User; -import im.vector.matrix.android.internal.legacy.rest.model.filter.RoomEventFilter; -import im.vector.matrix.android.internal.legacy.rest.model.message.Message; -import im.vector.matrix.android.internal.legacy.rest.model.sync.RoomResponse; - -/** - * Class used to make requests to the rooms API. - */ -public class RoomsRestClient extends RestClient { - - public static final int DEFAULT_MESSAGES_PAGINATION_LIMIT = 30; - - // read marker field names - private static final String READ_MARKER_FULLY_READ = "m.fully_read"; - private static final String READ_MARKER_READ = "m.read"; - - /** - * {@inheritDoc} - */ - public RoomsRestClient(SessionParams sessionParams) { - super(sessionParams, RoomsApi.class, RestClient.URI_API_PREFIX_PATH_R0, false); - } - - /** - * Send a message to room - * - * @param transactionId the unique transaction id (it should avoid duplicated messages) - * @param roomId the room id - * @param message the message - * @param callback the callback containing the created event if successful - */ - public void sendMessage(final String transactionId, final String roomId, final Message message, final ApiCallback callback) { - // privacy - // final String description = "SendMessage : roomId " + roomId + " - message " + message.body; - final String description = "SendMessage : roomId " + roomId; - - // the messages have their dedicated method in MXSession to be resent if there is no available network - mApi.sendMessage(transactionId, roomId, message) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - sendMessage(transactionId, roomId, message, callback); - } - })); - } - - /** - * Send an event to a room. - * - * @param transactionId the unique transaction id (it should avoid duplicated messages) - * @param roomId the room id - * @param eventType the type of event - * @param content the event content - * @param callback the callback containing the created event if successful - */ - public void sendEventToRoom(final String transactionId, - final String roomId, - final String eventType, - final JsonObject content, - final ApiCallback callback) { - // privacy - //final String description = "sendEvent : roomId " + roomId + " - eventType " + eventType + " content " + content; - final String description = "sendEvent : roomId " + roomId + " - eventType " + eventType; - - // do not retry the call invite - // it might trigger weird behaviour on flaggy networks - if (!TextUtils.equals(eventType, Event.EVENT_TYPE_CALL_INVITE)) { - mApi.send(transactionId, roomId, eventType, content) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - sendEventToRoom(transactionId, roomId, eventType, content, callback); - } - })); - } else { - mApi.send(transactionId, roomId, eventType, content) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, null)); - } - } - - /** - * Get a limited amount of messages, for the given room starting from the given token. - * The amount of message is set to {@link #DEFAULT_MESSAGES_PAGINATION_LIMIT}. - * - * @param roomId the room id - * @param fromToken the token identifying the message to start from Required. - * @param direction the direction. Required. - * @param limit the maximum number of messages to retrieve. - * @param roomEventFilter A RoomEventFilter to filter returned events with. Optional. - * @param callback the callback called with the response. Messages will be returned in reverse order. - */ - public void getRoomMessagesFrom(final String roomId, - final String fromToken, - final EventTimeline.Direction direction, - final int limit, - @Nullable final RoomEventFilter roomEventFilter, - final ApiCallback callback) { - final String description = "messagesFrom : roomId " + roomId + " fromToken " + fromToken + "with direction " + direction + " with limit " + limit; - - mApi.getRoomMessagesFrom(roomId, fromToken, (direction == EventTimeline.Direction.BACKWARDS) ? "b" : "f", limit, toJson(roomEventFilter)) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, - new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getRoomMessagesFrom(roomId, fromToken, direction, limit, roomEventFilter, callback); - } - })); - } - - /** - * Invite a user to a room. - * - * @param roomId the room id - * @param userId the user id - * @param callback the async callback - */ - public void inviteUserToRoom(final String roomId, final String userId, final ApiCallback callback) { - final String description = "inviteToRoom : roomId " + roomId + " userId " + userId; - - // TODO Do not create a User for this - User user = new User(); - user.user_id = userId; - - mApi.invite(roomId, user) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - inviteUserToRoom(roomId, userId, callback); - } - })); - } - - /** - * Invite a user by his email address to a room. - * - * @param roomId the room id - * @param email the email - * @param callback the async callback - */ - public void inviteByEmailToRoom(final String roomId, final String email, final ApiCallback callback) { - inviteThreePidToRoom("email", email, roomId, callback); - } - - /** - * Invite an user from a 3Pids. - * - * @param medium the medium - * @param address the address - * @param roomId the room id - * @param callback the async callback - */ - private void inviteThreePidToRoom(final String medium, final String address, final String roomId, final ApiCallback callback) { - // privacy - //final String description = "inviteThreePidToRoom : medium " + medium + " address " + address + " roomId " + roomId; - final String description = "inviteThreePidToRoom : medium " + medium + " roomId " + roomId; - - // This request must not have the protocol part - String identityServer = mHsConfig.getIdentityServerUri().toString(); - - if (identityServer.startsWith("http://")) { - identityServer = identityServer.substring("http://".length()); - } else if (identityServer.startsWith("https://")) { - identityServer = identityServer.substring("https://".length()); - } - - Map parameters = new HashMap<>(); - parameters.put("id_server", identityServer); - parameters.put("medium", medium); - parameters.put("address", address); - - mApi.invite(roomId, parameters) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - inviteThreePidToRoom(medium, address, roomId, callback); - } - })); - } - - /** - * Join a room by its roomAlias or its roomId. - * - * @param roomIdOrAlias the room id or the room alias - * @param callback the async callback - */ - public void joinRoom(final String roomIdOrAlias, final ApiCallback callback) { - joinRoom(roomIdOrAlias, null, callback); - } - - /** - * Join a room by its roomAlias or its roomId with some parameters. - * - * @param roomIdOrAlias the room id or the room alias - * @param params the joining parameters. - * @param callback the async callback - */ - public void joinRoom(final String roomIdOrAlias, final Map params, final ApiCallback callback) { - final String description = "joinRoom : roomId " + roomIdOrAlias; - - mApi.joinRoomByAliasOrId(roomIdOrAlias, (null == params) ? new HashMap() : params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - joinRoom(roomIdOrAlias, params, callback); - } - })); - } - - /** - * Leave a room. - * - * @param roomId the room id - * @param callback the async callback - */ - public void leaveRoom(final String roomId, final ApiCallback callback) { - final String description = "leaveRoom : roomId " + roomId; - - mApi.leave(roomId, new JsonObject()) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - leaveRoom(roomId, callback); - } - })); - } - - /** - * Forget a room. - * - * @param roomId the room id - * @param callback the async callback - */ - public void forgetRoom(final String roomId, final ApiCallback callback) { - final String description = "forgetRoom : roomId " + roomId; - - mApi.forget(roomId, new JsonObject()) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - forgetRoom(roomId, callback); - } - })); - } - - /** - * Kick a user from a room. - * - * @param roomId the room id - * @param userId the user id - * @param callback the async callback - */ - public void kickFromRoom(final String roomId, final String userId, final ApiCallback callback) { - final String description = "kickFromRoom : roomId " + roomId + " userId " + userId; - - // TODO It does not look like this in the Matrix spec - // Kicking is done by posting that the user is now in a "leave" state - RoomMember member = new RoomMember(); - member.membership = RoomMember.MEMBERSHIP_LEAVE; - - mApi.updateRoomMember(roomId, userId, member) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - kickFromRoom(roomId, userId, callback); - } - })); - } - - /** - * Ban a user from a room. - * - * @param roomId the room id - * @param user the banned user object (userId and reason for ban) - * @param callback the async callback - */ - public void banFromRoom(final String roomId, final BannedUser user, final ApiCallback callback) { - final String description = "banFromRoom : roomId " + roomId + " userId " + user.userId; - - mApi.ban(roomId, user) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - banFromRoom(roomId, user, callback); - } - })); - } - - /** - * Unban an user from a room. - * - * @param roomId the room id - * @param user the banned user (userId) - * @param callback the async callback - */ - public void unbanFromRoom(final String roomId, final BannedUser user, final ApiCallback callback) { - final String description = "Unban : roomId " + roomId + " userId " + user.userId; - - mApi.unban(roomId, user) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - unbanFromRoom(roomId, user, callback); - } - })); - } - - /** - * Create a new room. - * - * @param params the room creation parameters - * @param callback the async callback - */ - public void createRoom(final CreateRoomParams params, final ApiCallback callback) { - // privacy - //final String description = "createRoom : name " + name + " topic " + topic; - final String description = "createRoom"; - - mApi.createRoom(params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, - new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - createRoom(params, callback); - } - })); - } - - /** - * Perform an initial sync on the room - * - * @param roomId the room id - * @param callback the async callback - */ - public void initialSync(final String roomId, final ApiCallback callback) { - final String description = "initialSync : roomId " + roomId; - - mApi.initialSync(roomId, DEFAULT_MESSAGES_PAGINATION_LIMIT) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - initialSync(roomId, callback); - } - })); - } - - /** - * Retrieve an event from its room id / event id. - * - * @param roomId the room id - * @param eventId the event id - * @param callback the asynchronous callback. - */ - public void getEvent(final String roomId, final String eventId, final ApiCallback callback) { - // try first with roomid / event id - getEventFromRoomIdEventId(roomId, eventId, new SimpleApiCallback(callback) { - @Override - public void onSuccess(Event event) { - callback.onSuccess(event); - } - - @Override - public void onMatrixError(MatrixError e) { - if (TextUtils.equals(e.errcode, MatrixError.UNRECOGNIZED)) { - // Try to retrieve the event using the context API - // It's ok to pass null as a filter here - getContextOfEvent(roomId, eventId, 1, null, new SimpleApiCallback(callback) { - @Override - public void onSuccess(EventContext eventContext) { - callback.onSuccess(eventContext.event); - } - }); - } else { - callback.onMatrixError(e); - } - } - }); - } - - /** - * Retrieve an event from its room id / event id. - * - * @param roomId the room id - * @param eventId the event id - * @param callback the asynchronous callback. - */ - private void getEventFromRoomIdEventId(final String roomId, final String eventId, final ApiCallback callback) { - final String description = "getEventFromRoomIdEventId : roomId " + roomId + " eventId " + eventId; - - mApi.getEvent(roomId, eventId) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getEventFromRoomIdEventId(roomId, eventId, callback); - } - })); - } - - /** - * Get the context surrounding an event. - * - * @param roomId the room id - * @param eventId the event Id - * @param limit the maximum number of messages to retrieve - * @param roomEventFilter A RoomEventFilter to filter returned events with. Optional. - * @param callback the asynchronous callback called with the response - */ - public void getContextOfEvent(final String roomId, - final String eventId, - final int limit, - @Nullable final RoomEventFilter roomEventFilter, - final ApiCallback callback) { - final String description = "getContextOfEvent : roomId " + roomId + " eventId " + eventId + " limit " + limit; - - mApi.getContextOfEvent(roomId, eventId, limit, toJson(roomEventFilter)) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getContextOfEvent(roomId, eventId, limit, roomEventFilter, callback); - } - })); - } - - /** - * Update the room name. - * - * @param roomId the room id - * @param name the room name - * @param callback the async callback - */ - public void updateRoomName(final String roomId, final String name, final ApiCallback callback) { - final String description = "updateName : roomId " + roomId + " name " + name; - - Map params = new HashMap<>(); - params.put("name", name); - - mApi.sendStateEvent(roomId, Event.EVENT_TYPE_STATE_ROOM_NAME, params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - updateRoomName(roomId, name, callback); - } - })); - } - - /** - * Update the canonical alias. - * - * @param roomId the room id - * @param canonicalAlias the canonical alias - * @param callback the async callback - */ - public void updateCanonicalAlias(final String roomId, final String canonicalAlias, final ApiCallback callback) { - final String description = "updateCanonicalAlias : roomId " + roomId + " canonicalAlias " + canonicalAlias; - - Map params = new HashMap<>(); - params.put("alias", canonicalAlias); - - mApi.sendStateEvent(roomId, Event.EVENT_TYPE_STATE_CANONICAL_ALIAS, params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - updateCanonicalAlias(roomId, canonicalAlias, callback); - } - })); - } - - /** - * Update history visibility. - * - * @param roomId the room id - * @param aVisibility the visibility - * @param callback the async callback - */ - public void updateHistoryVisibility(final String roomId, final String aVisibility, final ApiCallback callback) { - final String description = "updateHistoryVisibility : roomId " + roomId + " visibility " + aVisibility; - - Map params = new HashMap<>(); - params.put("history_visibility", aVisibility); - - mApi.sendStateEvent(roomId, Event.EVENT_TYPE_STATE_HISTORY_VISIBILITY, params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - updateHistoryVisibility(roomId, aVisibility, callback); - } - })); - } - - /** - * Update the directory visibility of the room. - * - * @param aRoomId the room id - * @param aDirectoryVisibility the visibility of the room in the directory list - * @param callback the async callback response - */ - public void updateDirectoryVisibility(final String aRoomId, final String aDirectoryVisibility, final ApiCallback callback) { - final String description = "updateRoomDirectoryVisibility : roomId=" + aRoomId + " visibility=" + aDirectoryVisibility; - - RoomDirectoryVisibility roomDirectoryVisibility = new RoomDirectoryVisibility(); - roomDirectoryVisibility.visibility = aDirectoryVisibility; - - mApi.setRoomDirectoryVisibility(aRoomId, roomDirectoryVisibility) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - updateDirectoryVisibility(aRoomId, aDirectoryVisibility, callback); - } - })); - } - - - /** - * Get the directory visibility of the room (see {@link #updateDirectoryVisibility(String, String, ApiCallback)}). - * - * @param aRoomId the room ID - * @param callback on success callback containing a the room directory visibility - */ - public void getDirectoryVisibility(final String aRoomId, final ApiCallback callback) { - final String description = "getDirectoryVisibility roomId=" + aRoomId; - - mApi.getRoomDirectoryVisibility(aRoomId) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, - new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getDirectoryVisibility(aRoomId, callback); - } - })); - } - - /** - * Get the room members - * - * @param roomId the room id where to get the members - * @param syncToken the sync token (optional) - * @param membership to include only one type of membership (optional) - * @param notMembership to exclude one type of membership (optional) - * @param callback the callback - */ - public void getRoomMembers(final String roomId, - @Nullable final String syncToken, - @Nullable final String membership, - @Nullable final String notMembership, - final ApiCallback callback) { - final String description = "getRoomMembers roomId=" + roomId; - - mApi.getMembers(roomId, syncToken, membership, notMembership) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getRoomMembers(roomId, syncToken, membership, notMembership, callback); - } - })); - } - - /** - * Update the room topic. - * - * @param roomId the room id - * @param topic the room topic - * @param callback the async callback - */ - public void updateTopic(final String roomId, final String topic, final ApiCallback callback) { - final String description = "updateTopic : roomId " + roomId + " topic " + topic; - - Map params = new HashMap<>(); - params.put("topic", topic); - - mApi.sendStateEvent(roomId, Event.EVENT_TYPE_STATE_ROOM_TOPIC, params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - updateTopic(roomId, topic, callback); - } - })); - } - - /** - * Redact an event. - * - * @param roomId the room id - * @param eventId the event id - * @param callback the callback containing the created event if successful - */ - public void redactEvent(final String roomId, final String eventId, final ApiCallback callback) { - final String description = "redactEvent : roomId " + roomId + " eventId " + eventId; - - mApi.redactEvent(roomId, eventId, new JsonObject()) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - redactEvent(roomId, eventId, callback); - } - })); - } - - /** - * Report an event. - * - * @param roomId the room id - * @param eventId the event id - * @param score the metric to let the user rate the severity of the abuse. It ranges from -100 “most offensive” to 0 “inoffensive” - * @param reason the reason - * @param callback the callback - */ - public void reportEvent(final String roomId, final String eventId, final int score, final String reason, final ApiCallback callback) { - final String description = "report : roomId " + roomId + " eventId " + eventId; - - ReportContentParams content = new ReportContentParams(); - - content.score = score; - content.reason = reason; - - mApi.reportEvent(roomId, eventId, content) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - reportEvent(roomId, eventId, score, reason, callback); - } - })); - } - - /** - * Update the power levels. - * - * @param roomId the room id - * @param powerLevels the new powerLevels - * @param callback the async callback - */ - public void updatePowerLevels(final String roomId, final PowerLevels powerLevels, final ApiCallback callback) { - final String description = "updatePowerLevels : roomId " + roomId + " powerLevels " + powerLevels; - - mApi.setPowerLevels(roomId, powerLevels) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - updatePowerLevels(roomId, powerLevels, callback); - } - })); - } - - /** - * Send a state events. - * - * @param roomId the dedicated room id - * @param eventType the event type - * @param stateKey the state key - * @param params the put parameters - * @param callback the asynchronous callback - */ - public void sendStateEvent(final String roomId, - final String eventType, - @Nullable final String stateKey, - final Map params, - final ApiCallback callback) { - final String description = "sendStateEvent : roomId " + roomId + " - eventType " + eventType; - - if (null != stateKey) { - mApi.sendStateEvent(roomId, eventType, stateKey, params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - sendStateEvent(roomId, eventType, stateKey, params, callback); - } - })); - } else { - mApi.sendStateEvent(roomId, eventType, params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - sendStateEvent(roomId, eventType, null, params, callback); - } - })); - } - } - - /** - * Looks up the contents of a state event in a room - * - * @param roomId the room id - * @param eventType the event type - * @param callback the asynchronous callback - */ - public void getStateEvent(final String roomId, final String eventType, final ApiCallback callback) { - final String description = "getStateEvent : roomId " + roomId + " eventId " + eventType; - - mApi.getStateEvent(roomId, eventType) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getStateEvent(roomId, eventType, callback); - } - })); - } - - /** - * Looks up the contents of a state event in a room - * - * @param roomId the room id - * @param eventType the event type - * @param stateKey the key of the state to look up - * @param callback the asynchronous callback - */ - public void getStateEvent(final String roomId, final String eventType, final String stateKey, final ApiCallback callback) { - final String description = "getStateEvent : roomId " + roomId + " eventId " + eventType + " stateKey " + stateKey; - - mApi.getStateEvent(roomId, eventType, stateKey) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getStateEvent(roomId, eventType, stateKey, callback); - } - })); - } - - /** - * send typing notification. - * - * @param roomId the room id - * @param userId the user id - * @param isTyping true if the user is typing - * @param timeout the typing event timeout - * @param callback the asynchronous callback - */ - public void sendTypingNotification(String roomId, String userId, boolean isTyping, int timeout, ApiCallback callback) { - final String description = "sendTypingNotification : roomId " + roomId + " isTyping " + isTyping; - - Typing typing = new Typing(); - typing.typing = isTyping; - - if (-1 != timeout) { - typing.timeout = timeout; - } - - // never resend typing on network error - mApi.setTypingNotification(roomId, userId, typing) - .enqueue(new RestAdapterCallback(description, null, callback, null)); - } - - /** - * Update the room avatar url. - * - * @param roomId the room id - * @param avatarUrl canonical alias - * @param callback the async callback - */ - public void updateAvatarUrl(final String roomId, final String avatarUrl, final ApiCallback callback) { - final String description = "updateAvatarUrl : roomId " + roomId + " avatarUrl " + avatarUrl; - - Map params = new HashMap<>(); - params.put("url", avatarUrl); - - mApi.sendStateEvent(roomId, Event.EVENT_TYPE_STATE_ROOM_AVATAR, params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - updateAvatarUrl(roomId, avatarUrl, callback); - } - })); - } - - /** - * Send a read markers. - * - * @param roomId the room id - * @param rmEventId the read marker event Id - * @param rrEventId the read receipt event Id - * @param callback the callback - */ - public void sendReadMarker(final String roomId, final String rmEventId, final String rrEventId, final ApiCallback callback) { - final String description = "sendReadMarker : roomId " + roomId + " - rmEventId " + rmEventId + " -- rrEventId " + rrEventId; - final Map params = new HashMap<>(); - - if (!TextUtils.isEmpty(rmEventId)) { - params.put(READ_MARKER_FULLY_READ, rmEventId); - } - - if (!TextUtils.isEmpty(rrEventId)) { - params.put(READ_MARKER_READ, rrEventId); - } - - mApi.sendReadMarker(roomId, params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, true, callback, - new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - sendReadMarker(roomId, rmEventId, rrEventId, callback); - } - })); - } - - /** - * Add a tag to a room. - * Use this method to update the order of an existing tag. - * - * @param roomId the roomId - * @param tag the new tag to add to the room. - * @param order the order. - * @param callback the operation callback - */ - public void addTag(final String roomId, final String tag, final Double order, final ApiCallback callback) { - final String description = "addTag : roomId " + roomId + " - tag " + tag + " - order " + order; - - Map hashMap = new HashMap<>(); - hashMap.put("order", order); - - mApi.addTag(mCredentials.getUserId(), roomId, tag, hashMap) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - addTag(roomId, tag, order, callback); - } - })); - } - - /** - * Remove a tag to a room. - * - * @param roomId the roomId - * @param tag the new tag to add to the room. - * @param callback the operation callback - */ - public void removeTag(final String roomId, final String tag, final ApiCallback callback) { - final String description = "removeTag : roomId " + roomId + " - tag " + tag; - - mApi.removeTag(mCredentials.getUserId(), roomId, tag) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - removeTag(roomId, tag, callback); - } - })); - } - - /** - * Update the URL preview status - * - * @param roomId the roomId - * @param status the new status - * @param callback the operation callback - */ - public void updateURLPreviewStatus(final String roomId, final boolean status, final ApiCallback callback) { - final String description = "updateURLPreviewStatus : roomId " + roomId + " - status " + status; - - Map params = new HashMap<>(); - params.put(AccountDataRestClient.ACCOUNT_DATA_KEY_URL_PREVIEW_DISABLE, !status); - - mApi.updateAccountData(mCredentials.getUserId(), roomId, Event.EVENT_TYPE_URL_PREVIEW, params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - updateURLPreviewStatus(roomId, status, callback); - } - })); - } - - /** - * Get the room ID corresponding to this room alias. - * - * @param roomAlias the room alias. - * @param callback the operation callback - */ - public void getRoomIdByAlias(final String roomAlias, final ApiCallback callback) { - final String description = "getRoomIdByAlias : " + roomAlias; - - mApi.getRoomIdByAlias(roomAlias) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, - new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getRoomIdByAlias(roomAlias, callback); - } - })); - } - - /** - * Set the room ID corresponding to a room alias. - * - * @param roomId the room id. - * @param roomAlias the room alias. - * @param callback the operation callback - */ - public void setRoomIdByAlias(final String roomId, final String roomAlias, final ApiCallback callback) { - final String description = "setRoomIdByAlias : roomAlias " + roomAlias + " - roomId : " + roomId; - - RoomAliasDescription roomAliasDescription = new RoomAliasDescription(); - roomAliasDescription.room_id = roomId; - - mApi.setRoomIdByAlias(roomAlias, roomAliasDescription) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - setRoomIdByAlias(roomId, roomAlias, callback); - } - })); - } - - /** - * Remove the room alias. - * - * @param roomAlias the room alias. - * @param callback the room alias description - */ - public void removeRoomAlias(final String roomAlias, final ApiCallback callback) { - final String description = "removeRoomAlias : " + roomAlias; - - mApi.removeRoomAlias(roomAlias) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - removeRoomAlias(roomAlias, callback); - } - })); - } - - /** - * Update the join rule of the room. - * To make the room private, the aJoinRule must be set to {@link RoomState#JOIN_RULE_INVITE}. - * - * @param aRoomId the room id - * @param aJoinRule the join rule: {@link RoomState#JOIN_RULE_PUBLIC} or {@link RoomState#JOIN_RULE_INVITE} - * @param callback the async callback response - */ - public void updateJoinRules(final String aRoomId, final String aJoinRule, final ApiCallback callback) { - final String description = "updateJoinRules : roomId=" + aRoomId + " rule=" + aJoinRule; - - Map params = new HashMap<>(); - params.put("join_rule", aJoinRule); - - mApi.sendStateEvent(aRoomId, Event.EVENT_TYPE_STATE_ROOM_JOIN_RULES, params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - updateJoinRules(aRoomId, aJoinRule, callback); - } - })); - } - - /** - * Update the guest access rule of the room. - * To deny guest access to the room, aGuestAccessRule must be set to {@link RoomState#GUEST_ACCESS_FORBIDDEN} - * - * @param aRoomId the room id - * @param aGuestAccessRule the guest access rule: {@link RoomState#GUEST_ACCESS_CAN_JOIN} or {@link RoomState#GUEST_ACCESS_FORBIDDEN} - * @param callback the async callback response - */ - public void updateGuestAccess(final String aRoomId, final String aGuestAccessRule, final ApiCallback callback) { - final String description = "updateGuestAccess : roomId=" + aRoomId + " rule=" + aGuestAccessRule; - - Map params = new HashMap<>(); - params.put("guest_access", aGuestAccessRule); - - mApi.sendStateEvent(aRoomId, Event.EVENT_TYPE_STATE_ROOM_GUEST_ACCESS, params) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - updateGuestAccess(aRoomId, aGuestAccessRule, callback); - } - })); - } - - @Nullable - private String toJson(@Nullable RoomEventFilter roomEventFilter) { - if (roomEventFilter == null) { - return null; - } - - return roomEventFilter.toJSONString(); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/ThirdPidRestClient.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/ThirdPidRestClient.java deleted file mode 100644 index 65ed7630..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/ThirdPidRestClient.java +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.client; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import im.vector.matrix.android.api.auth.data.SessionParams; -import im.vector.matrix.android.internal.legacy.RestClient; -import im.vector.matrix.android.internal.legacy.rest.api.ThirdPidApi; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.DefaultRetrofit2ResponseHandler; -import im.vector.matrix.android.internal.legacy.rest.model.BulkLookupParams; -import im.vector.matrix.android.internal.legacy.rest.model.BulkLookupResponse; -import im.vector.matrix.android.internal.legacy.rest.model.HttpError; -import im.vector.matrix.android.internal.legacy.rest.model.HttpException; -import im.vector.matrix.android.internal.legacy.rest.model.pid.PidResponse; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; - -public class ThirdPidRestClient extends RestClient { - - private static final String KEY_SUBMIT_TOKEN_SUCCESS = "success"; - - /** - * {@inheritDoc} - */ - public ThirdPidRestClient(SessionParams sessionParams) { - super(sessionParams, ThirdPidApi.class, URI_API_PREFIX_IDENTITY, false, true); - } - - /** - * Retrieve user matrix id from a 3rd party id. - * - * @param address 3rd party id - * @param medium the media. - * @param callback the 3rd party callback - */ - public void lookup3Pid(String address, String medium, final ApiCallback callback) { - mApi.lookup3Pid(address, medium).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - try { - handleLookup3PidResponse(response, callback); - } catch (IOException e) { - onFailure(call, e); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - callback.onUnexpectedError((Exception) t); - } - }); - } - - private void handleLookup3PidResponse( - Response response, - final ApiCallback callback - ) throws IOException { - DefaultRetrofit2ResponseHandler.handleResponse( - response, - new DefaultRetrofit2ResponseHandler.Listener() { - @Override - public void onSuccess(Response response) { - PidResponse pidResponse = response.body(); - callback.onSuccess((null == pidResponse.mxid) ? "" : pidResponse.mxid); - } - - @Override - public void onHttpError(HttpError httpError) { - callback.onNetworkError(new HttpException(httpError)); - } - } - ); - } - - - /** - * Request the ownership validation of an email address or a phone number previously set - * by {@link ProfileRestClient#requestEmailValidationToken(String, String, int, String, boolean, ApiCallback)} - * - * @param medium the medium of the 3pid - * @param token the token generated by the requestEmailValidationToken call - * @param clientSecret the client secret which was supplied in the requestEmailValidationToken call - * @param sid the sid for the session - * @param callback asynchronous callback response - */ - public void submitValidationToken(final String medium, - final String token, - final String clientSecret, - final String sid, - final ApiCallback callback) { - mApi.requestOwnershipValidation(medium, token, clientSecret, sid).enqueue(new Callback>() { - @Override - public void onResponse(Call> call, Response> response) { - try { - handleSubmitValidationTokenResponse(response, callback); - } catch (IOException e) { - callback.onUnexpectedError(e); - } - } - - @Override - public void onFailure(Call> call, Throwable t) { - callback.onUnexpectedError((Exception) t); - } - }); - } - - private void handleSubmitValidationTokenResponse( - Response> response, - final ApiCallback callback - ) throws IOException { - DefaultRetrofit2ResponseHandler.handleResponse( - response, - new DefaultRetrofit2ResponseHandler.Listener>() { - @Override - public void onSuccess(Response> response) { - Map aDataRespMap = response.body(); - if (aDataRespMap.containsKey(KEY_SUBMIT_TOKEN_SUCCESS)) { - callback.onSuccess((Boolean) aDataRespMap.get(KEY_SUBMIT_TOKEN_SUCCESS)); - } else { - callback.onSuccess(false); - } - } - - @Override - public void onHttpError(HttpError httpError) { - callback.onNetworkError(new HttpException(httpError)); - } - } - ); - } - - /** - * Retrieve user matrix id from a 3rd party id. - * - * @param addresses 3rd party ids - * @param mediums the medias. - * @param callback the 3rd parties callback - */ - public void lookup3Pids(final List addresses, final List mediums, final ApiCallback> callback) { - // sanity checks - if ((null == addresses) || (null == mediums) || (addresses.size() != mediums.size())) { - callback.onUnexpectedError(new Exception("invalid params")); - return; - } - - // nothing to check - if (0 == mediums.size()) { - callback.onSuccess(new ArrayList()); - return; - } - - BulkLookupParams threePidsParams = new BulkLookupParams(); - - List> list = new ArrayList<>(); - - for (int i = 0; i < addresses.size(); i++) { - list.add(Arrays.asList(mediums.get(i), addresses.get(i))); - } - - threePidsParams.threepids = list; - - mApi.bulkLookup(threePidsParams).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - try { - handleBulkLookupResponse(response, addresses, callback); - } catch (IOException e) { - callback.onUnexpectedError(e); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - callback.onUnexpectedError((Exception) t); - } - }); - } - - private void handleBulkLookupResponse( - Response response, - final List addresses, - final ApiCallback> callback - ) throws IOException { - DefaultRetrofit2ResponseHandler.handleResponse( - response, - new DefaultRetrofit2ResponseHandler.Listener() { - @Override - public void onSuccess(Response response) { - handleBulkLookupSuccess(response, addresses, callback); - } - - @Override - public void onHttpError(HttpError httpError) { - callback.onNetworkError(new HttpException(httpError)); - } - } - ); - } - - private void handleBulkLookupSuccess( - Response response, - List addresses, - ApiCallback> callback - ) { - BulkLookupResponse bulkLookupResponse = response.body(); - Map mxidByAddress = new HashMap<>(); - - if (null != bulkLookupResponse.threepids) { - for (int i = 0; i < bulkLookupResponse.threepids.size(); i++) { - List items = bulkLookupResponse.threepids.get(i); - // [0] : medium - // [1] : address - // [2] : matrix id - mxidByAddress.put(items.get(1), items.get(2)); - } - } - - List matrixIds = new ArrayList<>(); - - for (String address : addresses) { - if (mxidByAddress.containsKey(address)) { - matrixIds.add(mxidByAddress.get(address)); - } else { - matrixIds.add(""); - } - } - - callback.onSuccess(matrixIds); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/UrlPostTask.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/UrlPostTask.java deleted file mode 100644 index 64a2d99a..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/client/UrlPostTask.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.rest.client; - -import android.os.AsyncTask; - -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; - -import im.vector.matrix.android.internal.legacy.RestClient; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.URL; - -/** - * UrlPostTask triggers a POST with no param. - */ -public class UrlPostTask extends AsyncTask { - - public interface IPostTaskListener { - /** - * The post succeeds. - * - * @param object the object retrieves in the response. - */ - void onSucceed(JsonObject object); - - /** - * The post failed - * - * @param errorMessage thr error message - */ - void onError(String errorMessage); - } - - private static final String LOG_TAG = "UrlPostTask"; - - // the post listener - private IPostTaskListener mListener; - - @Override - protected String doInBackground(String... params) { - String result = ""; - - try { - URL url = new URL(params[0]); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - if (RestClient.getUserAgent() != null) { - conn.setRequestProperty("User-Agent", RestClient.getUserAgent()); - } - conn.setRequestMethod("POST"); - - InputStream is = new BufferedInputStream(conn.getInputStream()); - - if (is != null) { - result = convertStreamToString(is); - } - } catch (Exception e) { - // Do something about exceptions - result = e.getMessage(); - } - return result; - } - - /** - * Set the post listener - * - * @param listener the listener - */ - public void setListener(IPostTaskListener listener) { - mListener = listener; - } - - /** - * Convert a stream to a string - * - * @param is the input stream to convert - * @return the string - */ - private static String convertStreamToString(InputStream is) { - BufferedReader reader = new BufferedReader(new InputStreamReader(is)); - StringBuilder sb = new StringBuilder(); - - String line; - try { - while ((line = reader.readLine()) != null) { - sb.append(line + "\n"); - } - } catch (Exception e) { - Log.e(LOG_TAG, "convertStreamToString " + e.getMessage(), e); - } finally { - try { - is.close(); - } catch (Exception e) { - Log.e(LOG_TAG, "convertStreamToString finally failed " + e.getMessage(), e); - } - } - return sb.toString(); - } - - protected void onPostExecute(String result) { - JsonObject object = null; - - Log.d(LOG_TAG, "onPostExecute " + result); - - try { - JsonParser parser = new JsonParser(); - object = parser.parse(result).getAsJsonObject(); - } catch (Exception e) { - Log.e(LOG_TAG, "## onPostExecute() failed" + e.getMessage(), e); - } - - if (null != mListener) { - if (null != object) { - mListener.onSucceed(object); - } else { - mListener.onError(result); - } - } - } -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/json/BooleanDeserializer.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/json/BooleanDeserializer.java deleted file mode 100644 index cf00509c..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/json/BooleanDeserializer.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.rest.json; - -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonParseException; -import com.google.gson.JsonPrimitive; - -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.lang.reflect.Type; - -/** - * Convenient JsonDeserializer to accept various type of Boolean - */ -public class BooleanDeserializer implements JsonDeserializer { - - private static final String LOG_TAG = BooleanDeserializer.class.getSimpleName(); - - private final boolean mCanReturnNull; - - /** - * Constructor - * - * @param canReturnNull true if the deserializer can return null in case of error - */ - public BooleanDeserializer(boolean canReturnNull) { - mCanReturnNull = canReturnNull; - } - - /** - * @param json The Json data being deserialized - * @param typeOfT The type of the Object to deserialize to - * @param context not used - * @return true if json is: true, 1, "true" or "1". false for other values. null in other cases. - * @throws JsonParseException - */ - @Override - public Boolean deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { - if (json.isJsonPrimitive()) { - JsonPrimitive jsonPrimitive = json.getAsJsonPrimitive(); - - if (jsonPrimitive.isBoolean()) { - // Nominal case - return jsonPrimitive.getAsBoolean(); - } else if (jsonPrimitive.isNumber()) { - Log.w(LOG_TAG, "Boolean detected as a number"); - return jsonPrimitive.getAsInt() == 1; - } else if (jsonPrimitive.isString()) { - Log.w(LOG_TAG, "Boolean detected as a string"); - - String jsonPrimitiveString = jsonPrimitive.getAsString(); - return "1".equals(jsonPrimitiveString) - || "true".equals(jsonPrimitiveString); - } else { - // Should not happen - Log.e(LOG_TAG, "Unknown primitive"); - if (mCanReturnNull) { - return null; - } else { - return false; - } - } - } else if (json.isJsonNull()) { - if (mCanReturnNull) { - return null; - } else { - Log.w(LOG_TAG, "Boolean is null, but not allowed to return null"); - return false; - } - } - - Log.w(LOG_TAG, "Boolean detected as not a primitive type"); - if (mCanReturnNull) { - return null; - } else { - return false; - } - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/json/ConditionDeserializer.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/json/ConditionDeserializer.java deleted file mode 100644 index 7739d7e5..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/json/ConditionDeserializer.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.json; - -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; - -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.Condition; -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.ContainsDisplayNameCondition; -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.DeviceCondition; -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.EventMatchCondition; -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.RoomMemberCountCondition; -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.SenderNotificationPermissionCondition; -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.UnknownCondition; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.lang.reflect.Type; - -public class ConditionDeserializer implements JsonDeserializer { - private static final String LOG_TAG = ConditionDeserializer.class.getSimpleName(); - - @Override - public Condition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { - Condition condition = null; - - JsonObject jsonObject = json.getAsJsonObject(); - JsonElement kindElement = jsonObject.get("kind"); - - if (null != kindElement) { - String kind = kindElement.getAsString(); - - if (null != kind) { - switch (kind) { - case Condition.KIND_EVENT_MATCH: - condition = context.deserialize(json, EventMatchCondition.class); - break; - case Condition.KIND_DEVICE: - condition = context.deserialize(json, DeviceCondition.class); - break; - case Condition.KIND_CONTAINS_DISPLAY_NAME: - condition = context.deserialize(json, ContainsDisplayNameCondition.class); - break; - case Condition.KIND_ROOM_MEMBER_COUNT: - condition = context.deserialize(json, RoomMemberCountCondition.class); - break; - case Condition.KIND_SENDER_NOTIFICATION_PERMISSION: - condition = context.deserialize(json, SenderNotificationPermissionCondition.class); - break; - default: - Log.e(LOG_TAG, "## deserialize() : unsupported kind " + kind + " with value " + json); - condition = context.deserialize(json, UnknownCondition.class); - break; - } - } - } - return condition; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/json/MatrixFieldNamingStrategy.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/json/MatrixFieldNamingStrategy.java deleted file mode 100644 index c6c5db2d..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/json/MatrixFieldNamingStrategy.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.rest.json; - -import com.google.gson.FieldNamingStrategy; - -import java.lang.reflect.Field; -import java.util.Locale; - -/** - * Based on FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES. - * toLowerCase() is replaced by toLowerCase(Locale.ENGLISH). - * In some languages like turkish, toLowerCase does not provide the expected string. - * e.g _I is not converted to _i. - */ -public class MatrixFieldNamingStrategy implements FieldNamingStrategy { - - /** - * Converts the field name that uses camel-case define word separation into - * separate words that are separated by the provided {@code separatorString}. - */ - private static String separateCamelCase(String name, String separator) { - StringBuilder translation = new StringBuilder(); - for (int i = 0; i < name.length(); i++) { - char character = name.charAt(i); - if (Character.isUpperCase(character) && translation.length() != 0) { - translation.append(separator); - } - translation.append(character); - } - return translation.toString(); - } - - /** - * Translates the field name into its JSON field name representation. - * - * @param f the field object that we are translating - * @return the translated field name. - * @since 1.3 - */ - public String translateName(Field f) { - return separateCamelCase(f.getName(), "_").toLowerCase(Locale.ENGLISH); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/AuthParams.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/AuthParams.java deleted file mode 100644 index 086424fc..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/AuthParams.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model; - -import java.util.Map; - -/** - * Class to define the authentication parameters - */ -public class AuthParams { - // - public String type; - - // update password (type = m.login.password) - public String user; - public String password; - - // forget password parameters (type = m.login.email.identity) - public Map threepid_creds; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/BannedUser.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/BannedUser.java deleted file mode 100644 index cb970ad9..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/BannedUser.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model; - -/** - * Class to contain a banned user and the reason they were banned. - */ -public class BannedUser { - public String userId; - public String reason; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/BulkLookupParams.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/BulkLookupParams.java deleted file mode 100644 index d39d1ae2..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/BulkLookupParams.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2017 OpenMarket 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.matrix.android.internal.legacy.rest.model; - -import java.util.List; - -/** - * 3 pids request param - */ -public class BulkLookupParams { - // List of [medium, value] - public List> threepids; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/BulkLookupResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/BulkLookupResponse.java deleted file mode 100644 index 27fb21f0..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/BulkLookupResponse.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2017 OpenMarket 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.matrix.android.internal.legacy.rest.model; - -import java.util.List; - -/** - * 3 pids request response - */ -public class BulkLookupResponse { - // List of [medium, value, mxid] - public List> threepids; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ChangePasswordParams.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ChangePasswordParams.java deleted file mode 100644 index 12e7258c..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ChangePasswordParams.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model; - -/** - * Class to update the password - */ -public class ChangePasswordParams { - // current account information - public AuthParams auth; - // the new password - public String new_password; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ChunkEvents.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ChunkEvents.java deleted file mode 100644 index f6a02357..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ChunkEvents.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.rest.model; - -public class ChunkEvents extends ChunkResponse { -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ChunkResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ChunkResponse.java deleted file mode 100644 index 97163f85..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ChunkResponse.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.rest.model; - -import java.util.List; - -/** - * Class representing an API response with start and end tokens and a generically-typed chunk. - */ -public class ChunkResponse { - public List chunk; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ContentResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ContentResponse.java deleted file mode 100644 index b4c132ff..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ContentResponse.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model; - -public class ContentResponse { - - public String contentUri; - public int w; - public int h; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/CreateRoomParams.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/CreateRoomParams.java deleted file mode 100644 index 14cd2d17..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/CreateRoomParams.java +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model; - -import android.support.annotation.Nullable; -import android.text.TextUtils; - -import com.google.gson.annotations.SerializedName; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig; -import im.vector.matrix.android.api.auth.data.Credentials; -import im.vector.matrix.android.internal.legacy.MXPatterns; -import im.vector.matrix.android.internal.legacy.data.RoomState; -import im.vector.matrix.android.internal.legacy.rest.model.pid.Invite3Pid; -import im.vector.matrix.android.internal.legacy.rest.model.pid.ThreePid; -import im.vector.matrix.android.internal.legacy.util.JsonUtils; - -public class CreateRoomParams { - - public static final String PRESET_PRIVATE_CHAT = "private_chat"; - public static final String PRESET_PUBLIC_CHAT = "public_chat"; - public static final String PRESET_TRUSTED_PRIVATE_CHAT = "trusted_private_chat"; - - /** - * A public visibility indicates that the room will be shown in the published room list. - * A private visibility will hide the room from the published room list. - * Rooms default to private visibility if this key is not included. - * NB: This should not be confused with join_rules which also uses the word public. One of: ["public", "private"] - */ - public String visibility; - - /** - * The desired room alias local part. If this is included, a room alias will be created and mapped to the newly created room. - * The alias will belong on the same homeserver which created the room. - * For example, if this was set to "foo" and sent to the homeserver "example.com" the complete room alias would be #foo:example.com. - */ - @SerializedName("room_alias_name") - public String roomAliasName; - - /** - * If this is included, an m.room.name event will be sent into the room to indicate the name of the room. - * See Room Events for more information on m.room.name. - */ - public String name; - - /** - * If this is included, an m.room.topic event will be sent into the room to indicate the topic for the room. - * See Room Events for more information on m.room.topic. - */ - public String topic; - - /** - * A list of user IDs to invite to the room. - * This will tell the server to invite everyone in the list to the newly created room. - */ - @SerializedName("invite") - public List invitedUserIds; - - /** - * A list of objects representing third party IDs to invite into the room. - */ - @SerializedName("invite_3pid") - public List invite3pids; - - /** - * Extra keys to be added to the content of the m.room.create. - * The server will clobber the following keys: creator. - * Future versions of the specification may allow the server to clobber other keys. - */ - public Object creation_content; - - /** - * 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 presets, but gets overriden by name and topic keys. - */ - @SerializedName("initial_state") - public List initialStates; - - /** - * Convenience parameter for setting various default state events based on a preset. Must be either: - * private_chat => join_rules is set to invite. history_visibility is set to shared. - * trusted_private_chat => join_rules is set to invite. history_visibility is set to shared. All invitees are given the same power level as the - * room creator. - * public_chat: => join_rules is set to public. history_visibility is set to shared. One of: ["private_chat", "public_chat", "trusted_private_chat"] - */ - public String preset; - - /** - * This flag makes the server set the is_direct flag on the m.room.member events sent to the users in invite and invite_3pid. - * See Direct Messaging for more information. - */ - @SerializedName("is_direct") - public Boolean isDirect; - - /** - * Add the crypto algorithm to the room creation parameters. - * - * @param algorithm the algorithm - */ - public void addCryptoAlgorithm(String algorithm) { - if (!TextUtils.isEmpty(algorithm)) { - Event algoEvent = new Event(); - algoEvent.type = Event.EVENT_TYPE_MESSAGE_ENCRYPTION; - - Map contentMap = new HashMap<>(); - contentMap.put("algorithm", algorithm); - algoEvent.content = JsonUtils.getGson(false).toJsonTree(contentMap); - - if (null == initialStates) { - initialStates = Arrays.asList(algoEvent); - } else { - initialStates.add(algoEvent); - } - } - } - - /** - * Force the history visibility in the room creation parameters. - * - * @param historyVisibility the expected history visibility, set null to remove any existing value. - * see {@link RoomState#HISTORY_VISIBILITY_INVITED}, - * {@link RoomState#HISTORY_VISIBILITY_JOINED}, - * {@link RoomState#HISTORY_VISIBILITY_SHARED}, - * {@link RoomState#HISTORY_VISIBILITY_WORLD_READABLE} - */ - public void setHistoryVisibility(@Nullable String historyVisibility) { - if (!TextUtils.isEmpty(historyVisibility)) { - Event historyVisibilityEvent = new Event(); - historyVisibilityEvent.type = Event.EVENT_TYPE_STATE_HISTORY_VISIBILITY; - - Map contentMap = new HashMap<>(); - contentMap.put("history_visibility", historyVisibility); - historyVisibilityEvent.content = JsonUtils.getGson(false).toJsonTree(contentMap); - - if (null == initialStates) { - initialStates = Arrays.asList(historyVisibilityEvent); - } else { - initialStates.add(historyVisibilityEvent); - } - } else if (!initialStates.isEmpty()) { - final List newInitialStates = new ArrayList<>(); - for (Event event : initialStates) { - if (!event.type.equals(Event.EVENT_TYPE_STATE_HISTORY_VISIBILITY)) { - newInitialStates.add(event); - } - } - initialStates = newInitialStates; - } - } - - /** - * Mark as a direct message room. - */ - public void setDirectMessage() { - preset = CreateRoomParams.PRESET_TRUSTED_PRIVATE_CHAT; - isDirect = true; - } - - /** - * @return the invite count - */ - private int getInviteCount() { - return (null == invitedUserIds) ? 0 : invitedUserIds.size(); - } - - /** - * @return the pid invite count - */ - private int getInvite3PidCount() { - return (null == invite3pids) ? 0 : invite3pids.size(); - } - - /** - * Tells if the created room can be a direct chat one. - * - * @return true if it is a direct chat - */ - public boolean isDirect() { - return TextUtils.equals(preset, CreateRoomParams.PRESET_TRUSTED_PRIVATE_CHAT) - && (null != isDirect) - && isDirect - && (1 == getInviteCount() || (1 == getInvite3PidCount())); - } - - /** - * @return the first invited user id - */ - public String getFirstInvitedUserId() { - if (0 != getInviteCount()) { - return invitedUserIds.get(0); - } - - if (0 != getInvite3PidCount()) { - return invite3pids.get(0).address; - } - - return null; - } - - /** - * Add some ids to the room creation - * ids might be a matrix id or an email address. - * - * @param ids the participant ids to add. - */ - public void addParticipantIds(HomeServerConnectionConfig homeServerConnectionConfig, Credentials credentials, List ids) { - for (String id : ids) { - if (android.util.Patterns.EMAIL_ADDRESS.matcher(id).matches()) { - if (null == invite3pids) { - invite3pids = new ArrayList<>(); - } - - Invite3Pid pid = new Invite3Pid(); - pid.id_server = homeServerConnectionConfig.getIdentityServerUri().getHost(); - pid.medium = ThreePid.MEDIUM_EMAIL; - pid.address = id; - - invite3pids.add(pid); - } else if (MXPatterns.isUserId(id)) { - // do not invite oneself - if (!TextUtils.equals(credentials.getUserId(), id)) { - if (null == invitedUserIds) { - invitedUserIds = new ArrayList<>(); - } - - invitedUserIds.add(id); - } - - } // TODO add phonenumbers when it will be available - } - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/CreateRoomResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/CreateRoomResponse.java deleted file mode 100644 index 0f8516c0..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/CreateRoomResponse.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model; - -import com.google.gson.annotations.SerializedName; - -public class CreateRoomResponse { - @SerializedName("room_id") - public String roomId; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/CreatedEvent.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/CreatedEvent.java deleted file mode 100644 index 7b979dab..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/CreatedEvent.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.rest.model; - -import com.google.gson.annotations.SerializedName; - -public class CreatedEvent { - @SerializedName("event_id") - public String eventId; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/DeactivateAccountParams.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/DeactivateAccountParams.java deleted file mode 100644 index 0bf1454c..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/DeactivateAccountParams.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.rest.model; - -public class DeactivateAccountParams { - - // Auth params - public AuthParams auth; - - // Set to true to erase all data of the account - public boolean erase; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/EncryptedMediaScanBody.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/EncryptedMediaScanBody.java deleted file mode 100644 index 1bb60c0d..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/EncryptedMediaScanBody.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.rest.model; - -import com.google.gson.annotations.SerializedName; - -import im.vector.matrix.android.internal.legacy.rest.model.crypto.EncryptedFileInfo; - -/** - * Class to prepare the request body used to scan an encrypted content. - */ -public class EncryptedMediaScanBody { - // The encryption information used to decrypt the content before scanning it - @SerializedName("file") - public EncryptedFileInfo encryptedFileInfo; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/EncryptedMediaScanEncryptedBody.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/EncryptedMediaScanEncryptedBody.java deleted file mode 100644 index 2897e402..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/EncryptedMediaScanEncryptedBody.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.rest.model; - -import com.google.gson.annotations.SerializedName; - -import im.vector.matrix.android.internal.legacy.rest.model.crypto.EncryptedBodyFileInfo; - -/** - * Class to prepare the request body used to scan an encrypted content. - */ -public class EncryptedMediaScanEncryptedBody { - // The encrypted encryption information used to decrypt the content before scanning it - @SerializedName("encrypted_body") - public EncryptedBodyFileInfo encryptedBodyFileInfo; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/Event.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/Event.java deleted file mode 100644 index 71d9deef..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/Event.java +++ /dev/null @@ -1,1339 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model; - -import android.support.annotation.Nullable; -import android.text.TextUtils; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.annotations.SerializedName; - -import im.vector.matrix.android.internal.legacy.crypto.MXCryptoError; -import im.vector.matrix.android.internal.legacy.crypto.MXEventDecryptionResult; -import im.vector.matrix.android.internal.legacy.db.MXMediasCache; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.EncryptedFileInfo; -import im.vector.matrix.android.internal.legacy.rest.model.message.FileMessage; -import im.vector.matrix.android.internal.legacy.rest.model.message.ImageMessage; -import im.vector.matrix.android.internal.legacy.rest.model.message.LocationMessage; -import im.vector.matrix.android.internal.legacy.rest.model.message.Message; -import im.vector.matrix.android.internal.legacy.rest.model.message.StickerMessage; -import im.vector.matrix.android.internal.legacy.rest.model.message.VideoMessage; -import im.vector.matrix.android.internal.legacy.util.JsonUtils; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.io.Externalizable; -import java.io.IOException; -import java.io.ObjectInput; -import java.io.ObjectOutput; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.TimeZone; - -/** - * Generic event class with all possible fields for events. - */ -public class Event implements Externalizable { - private static final String LOG_TAG = Event.class.getSimpleName(); - - private static final long serialVersionUID = -1431845331022808337L; - - public enum SentState { - // the event has not been sent - UNSENT, - // the event is encrypting - ENCRYPTING, - // the event is currently sending - SENDING, - // the event is going to be resent asap - WAITING_RETRY, - // the event has been sent - SENT, - // The event failed to be sent - UNDELIVERED, - // the event failed to be sent because some unknown devices have been found while encrypting it - FAILED_UNKNOWN_DEVICES - } - - // when there is no more message to be paginated in a room - // the server returns a null token. - // defines by a non null one to be able to store it. - public static final String PAGINATE_BACK_TOKEN_END = "PAGINATE_BACK_TOKEN_END"; - - public static final String EVENT_TYPE_PRESENCE = "m.presence"; - public static final String EVENT_TYPE_MESSAGE = "m.room.message"; - public static final String EVENT_TYPE_STICKER = "m.sticker"; - public static final String EVENT_TYPE_MESSAGE_ENCRYPTED = "m.room.encrypted"; - public static final String EVENT_TYPE_MESSAGE_ENCRYPTION = "m.room.encryption"; - public static final String EVENT_TYPE_FEEDBACK = "m.room.message.feedback"; - public static final String EVENT_TYPE_TYPING = "m.typing"; - public static final String EVENT_TYPE_REDACTION = "m.room.redaction"; - public static final String EVENT_TYPE_RECEIPT = "m.receipt"; - public static final String EVENT_TYPE_TAGS = "m.tag"; - public static final String EVENT_TYPE_ROOM_KEY = "m.room_key"; - public static final String EVENT_TYPE_READ_MARKER = "m.fully_read"; - public static final String EVENT_TYPE_ROOM_PLUMBING = "m.room.plumbing"; - public static final String EVENT_TYPE_ROOM_BOT_OPTIONS = "m.room.bot.options"; - public static final String EVENT_TYPE_ROOM_KEY_REQUEST = "m.room_key_request"; - public static final String EVENT_TYPE_FORWARDED_ROOM_KEY = "m.forwarded_room_key"; - public static final String EVENT_TYPE_URL_PREVIEW = "org.matrix.room.preview_urls"; - - // State events - public static final String EVENT_TYPE_STATE_ROOM_NAME = "m.room.name"; - public static final String EVENT_TYPE_STATE_ROOM_TOPIC = "m.room.topic"; - public static final String EVENT_TYPE_STATE_ROOM_AVATAR = "m.room.avatar"; - public static final String EVENT_TYPE_STATE_ROOM_MEMBER = "m.room.member"; - public static final String EVENT_TYPE_STATE_ROOM_THIRD_PARTY_INVITE = "m.room.third_party_invite"; - public static final String EVENT_TYPE_STATE_ROOM_CREATE = "m.room.create"; - public static final String EVENT_TYPE_STATE_ROOM_JOIN_RULES = "m.room.join_rules"; - public static final String EVENT_TYPE_STATE_ROOM_GUEST_ACCESS = "m.room.guest_access"; - public static final String EVENT_TYPE_STATE_ROOM_POWER_LEVELS = "m.room.power_levels"; - public static final String EVENT_TYPE_STATE_ROOM_ALIASES = "m.room.aliases"; - public static final String EVENT_TYPE_STATE_ROOM_TOMBSTONE = "m.room.tombstone"; - public static final String EVENT_TYPE_STATE_CANONICAL_ALIAS = "m.room.canonical_alias"; - public static final String EVENT_TYPE_STATE_HISTORY_VISIBILITY = "m.room.history_visibility"; - public static final String EVENT_TYPE_STATE_RELATED_GROUPS = "m.room.related_groups"; - public static final String EVENT_TYPE_STATE_PINNED_EVENT = "m.room.pinned_events"; - - // call events - public static final String EVENT_TYPE_CALL_INVITE = "m.call.invite"; - public static final String EVENT_TYPE_CALL_CANDIDATES = "m.call.candidates"; - public static final String EVENT_TYPE_CALL_ANSWER = "m.call.answer"; - public static final String EVENT_TYPE_CALL_HANGUP = "m.call.hangup"; - - public static final long DUMMY_EVENT_AGE = Long.MAX_VALUE - 1; - - /** - * Type of the event - * Warning, consider using {@link #getType()} to get the type of the unencrypted event - */ - public String type; - - public transient JsonElement content = null; - private String contentAsString = null; - - public transient JsonElement prev_content = null; - private String prev_content_as_string = null; - - public String eventId; - public String roomId; - // former Sync V1 sender name - public String userId; - // Sync V2 sender name - public String sender; - public long originServerTs; - public Long age; - - // Specific to state events - @SerializedName("state_key") - public String stateKey; - - // Contains optional extra information about the event. - public UnsignedData unsigned; - - // Specific to redaction - public String redacts; - - // A subset of the state of the room at the time of the invite, if membership is invite - public List invite_room_state; - - // store the exception triggered when unsent - public Exception unsentException = null; - public MatrixError unsentMatrixError = null; - - // sent state - public SentState mSentState; - - // save the token to back paginate - // the room history could have been reduced to save memory. - // so store the token from each event. - public String mToken; - - // The file cache uses the token as a pagination marker. - // When the user paginates, the file cache paginate until to find X events or an event with a token. - // This token must be used to perform a server catchup. - public boolean mIsInternalPaginationToken; - - // store the linked matrix id - private String mMatrixId; - - // the time raw offset (time zone management) - private long mTimeZoneRawOffset = 0; - - private long getTimeZoneOffset() { - return TimeZone.getDefault().getRawOffset(); - } - - /** - * Default constructor - */ - public Event() { - type = null; - content = null; - prev_content = null; - mIsInternalPaginationToken = false; - - userId = roomId = eventId = null; - originServerTs = 0; - age = null; - - mTimeZoneRawOffset = getTimeZoneOffset(); - - stateKey = null; - redacts = null; - - unsentMatrixError = null; - unsentException = null; - - mMatrixId = null; - - mSentState = SentState.SENT; - } - - /** - * @return the sender - */ - public String getSender() { - return (null == sender) ? userId : sender; - } - - /** - * Update the sender - * - * @param aSender the new sender - */ - public void setSender(String aSender) { - sender = userId = aSender; - } - - /** - * Update the matrix Id. - * - * @param aMatrixId the new matrix id. - */ - public void setMatrixId(String aMatrixId) { - mMatrixId = aMatrixId; - } - - /** - * @return the matrix id. - */ - public String getMatrixId() { - return mMatrixId; - } - - static final long MAX_ORIGIN_SERVER_TS = 1L << 50L; - - /** - * @return true if originServerTs is valid. - */ - public boolean isValidOriginServerTs() { - return originServerTs < MAX_ORIGIN_SERVER_TS; - } - - /** - * @return the originServerTs. - */ - public long getOriginServerTs() { - return originServerTs; - } - - /** - * Update the event content. - * - * @param newContent the new content. - */ - public void updateContent(JsonElement newContent) { - content = newContent; - contentAsString = null; - } - - /** - * @return true if content has some entries - */ - public boolean hasContentFields() { - boolean res = false; - JsonObject json = getContentAsJsonObject(); - - if (null != json) { - Set> entries = getContentAsJsonObject().entrySet(); - - res = (null != entries) && (0 != entries.size()); - } - return res; - } - - /** - * @return true if this event was redacted - */ - public boolean isRedacted() { - return (null != unsigned) && (null != unsigned.redacted_because); - } - - static DateFormat mDateFormat = null; - static long mFormatterRawOffset = 1234; - - /** - * @return a formatted timestamp. - */ - public String formattedOriginServerTs() { - // avoid displaying weird origin ts - if (!isValidOriginServerTs()) { - return " "; - } else { - // the formatter must be updated if the timezone has been updated - // else the formatted string are wrong (does not use the current timezone) - if ((null == mDateFormat) || (mFormatterRawOffset != getTimeZoneOffset())) { - mDateFormat = new SimpleDateFormat("MMM d HH:mm", Locale.getDefault()); - mFormatterRawOffset = getTimeZoneOffset(); - } - - return mDateFormat.format(new Date(getOriginServerTs())); - } - } - - /** - * Update the originServerTs. - * - * @param anOriginServer the new originServerTs. - */ - public void setOriginServerTs(long anOriginServer) { - originServerTs = anOriginServer; - } - - /** - * @return the event type - */ - public String getType() { - if (null != mClearEvent) { - return mClearEvent.type; - } else { - return type; - } - } - - /** - * Update the event type - * - * @param aType the new type - */ - public void setType(String aType) { - // TODO manage encryption - type = aType; - } - - /** - * @return the wire event type - */ - public String getWireType() { - return type; - } - - /** - * @return the event content - */ - public JsonElement getContent() { - if (null != mClearEvent) { - return mClearEvent.getWireContent(); - } else { - return getWireContent(); - } - } - - /** - * @return the wired event content - */ - public JsonElement getWireContent() { - finalizeDeserialization(); - return content; - } - - /** - * @return a Json representation of the event - */ - public JsonObject toJsonObject() { - finalizeDeserialization(); - return JsonUtils.toJson(this); - } - - /** - * @return the content casted as JsonObject. - */ - @Nullable - public JsonObject getContentAsJsonObject() { - JsonElement cont = getContent(); - - if (null != cont && cont.isJsonObject()) { - return cont.getAsJsonObject(); - } - return null; - } - - /** - * @return the prev_content casted as JsonObject. - */ - public JsonObject getPrevContentAsJsonObject() { - finalizeDeserialization(); - - if ((null != unsigned) && (null != unsigned.prev_content)) { - // avoid getting two value for the same thing - if (null == prev_content) { - prev_content = unsigned.prev_content; - } - unsigned.prev_content = null; - } - - if ((null != prev_content) && prev_content.isJsonObject()) { - return prev_content.getAsJsonObject(); - } - return null; - } - - /** - * @return the content formatted as EventContent. - */ - public EventContent getEventContent() { - if (null != getContent()) { - return JsonUtils.toEventContent(getContent()); - } - return null; - } - - /** - * @return the content formatted as EventContent. - */ - public EventContent getWireEventContent() { - if (null != getWireContent()) { - return JsonUtils.toEventContent(getWireContent()); - } - return null; - } - - /** - * @return the content formatted as EventContent. - */ - public EventContent getPrevContent() { - if (null != getPrevContentAsJsonObject()) { - return JsonUtils.toEventContent(getPrevContentAsJsonObject()); - } - return null; - } - - /** - * @return the event age. - */ - public long getAge() { - if (null != age) { - return age; - } else if ((null != unsigned) && (null != unsigned.age)) { - age = unsigned.age; - return age; - } - - return Long.MAX_VALUE; - } - - /** - * @return the redacted event id. - */ - @Nullable - public String getRedactedEventId() { - if (null != redacts) { - return redacts; - } else if (isRedacted()) { - redacts = unsigned.redacted_because.redacts; - return redacts; - } - - return null; - } - - /** - * Create an event from a message. - * - * @param message the event content - * @param anUserId the event user Id - * @param aRoomId the vent room Id - */ - public Event(Message message, String anUserId, String aRoomId) { - type = Event.EVENT_TYPE_MESSAGE; - content = JsonUtils.toJson(message); - originServerTs = System.currentTimeMillis(); - sender = userId = anUserId; - roomId = aRoomId; - mSentState = Event.SentState.UNSENT; - createDummyEventId(); - } - - /** - * Create an event from a content and a type. - * - * @param aType the event type - * @param aContent the event content - * @param anUserId the event user Id - * @param aRoomId the vent room Id - */ - public Event(String aType, JsonObject aContent, String anUserId, String aRoomId) { - type = aType; - content = aContent; - originServerTs = System.currentTimeMillis(); - sender = userId = anUserId; - roomId = aRoomId; - mSentState = Event.SentState.UNSENT; - createDummyEventId(); - } - - /** - * Some events are not sent by the server. - * They are temporary stored until to get the server response. - */ - public void createDummyEventId() { - eventId = roomId + "-" + originServerTs; - age = DUMMY_EVENT_AGE; - } - - /** - * @return true if the event is a dummy id i.e this event has been created with createDummyEventId. - */ - public boolean isDummyEvent() { - return (roomId + "-" + originServerTs).equals(eventId); - } - - /** - * Update the pagination token. - * - * @param token the new token. - */ - public void setInternalPaginationToken(String token) { - mToken = token; - mIsInternalPaginationToken = true; - } - - /** - * @return true if the token has been set by setInternalPaginationToken. - */ - public boolean isInternalPaginationToken() { - return mIsInternalPaginationToken; - } - - /** - * @return true if the event has a token. - */ - public boolean hasToken() { - return (null != mToken) && !mIsInternalPaginationToken; - } - - /** - * @return true if the event if a call event. - */ - public boolean isCallEvent() { - return EVENT_TYPE_CALL_INVITE.equals(getType()) - || EVENT_TYPE_CALL_CANDIDATES.equals(getType()) - || EVENT_TYPE_CALL_ANSWER.equals(getType()) - || EVENT_TYPE_CALL_HANGUP.equals(getType()); - } - - /** - * Make a deep copy of this room state object. - * - * @return the copy - */ - public Event deepCopy() { - finalizeDeserialization(); - - Event copy = new Event(); - copy.type = type; - copy.content = content; - copy.contentAsString = contentAsString; - - copy.eventId = eventId; - copy.roomId = roomId; - copy.userId = userId; - copy.sender = sender; - copy.originServerTs = originServerTs; - copy.mTimeZoneRawOffset = mTimeZoneRawOffset; - copy.age = age; - - copy.stateKey = stateKey; - copy.prev_content = prev_content; - copy.prev_content_as_string = prev_content_as_string; - - copy.unsigned = unsigned; - copy.invite_room_state = invite_room_state; - copy.redacts = redacts; - - copy.mSentState = mSentState; - - copy.unsentException = unsentException; - copy.unsentMatrixError = unsentMatrixError; - - copy.mMatrixId = mMatrixId; - copy.mToken = mToken; - copy.mIsInternalPaginationToken = mIsInternalPaginationToken; - - return copy; - } - - /** - * Check if the current event can resent. - * - * @return true if it can be resent. - */ - public boolean canBeResent() { - return (mSentState == SentState.WAITING_RETRY) || (mSentState == SentState.UNDELIVERED) || (mSentState == SentState.FAILED_UNKNOWN_DEVICES); - } - - /** - * Check if the current event is encrypting. - * - * @return true if the message encryption is in progress. - */ - public boolean isEncrypting() { - return (mSentState == SentState.ENCRYPTING); - } - - /** - * Check if the current event is unsent. - * - * @return true if it is unsent. - */ - public boolean isUnsent() { - return (mSentState == SentState.UNSENT); - } - - /** - * Check if the current event is sending. - * - * @return true if it is sending. - */ - public boolean isSending() { - return (mSentState == SentState.SENDING) || (mSentState == SentState.WAITING_RETRY); - } - - /** - * Tell if the message sending failed - * - * @return true if the event has not been sent because of a failure - */ - public boolean isUndelivered() { - return (mSentState == SentState.UNDELIVERED); - } - - /** - * Tells if the message sending failed because some unknown devices have been detected. - * - * @return true if some unknown devices have been detected. - */ - public boolean isUnknownDevice() { - return (mSentState == SentState.FAILED_UNKNOWN_DEVICES); - } - - /** - * Check if the current event is sent. - * - * @return true if it is sent. - */ - public boolean isSent() { - return (mSentState == SentState.SENT); - } - - /** - * @return the media URLs defined in the event. - */ - public List getMediaUrls() { - List urls = new ArrayList<>(); - - if (Event.EVENT_TYPE_MESSAGE.equals(getType())) { - String msgType = JsonUtils.getMessageMsgType(getContent()); - - if (Message.MSGTYPE_IMAGE.equals(msgType)) { - ImageMessage imageMessage = JsonUtils.toImageMessage(getContent()); - - if (null != imageMessage.getUrl()) { - urls.add(imageMessage.getUrl()); - } - if (null != imageMessage.getThumbnailUrl()) { - urls.add(imageMessage.getThumbnailUrl()); - } - } else if (Message.MSGTYPE_FILE.equals(msgType) || Message.MSGTYPE_AUDIO.equals(msgType)) { - FileMessage fileMessage = JsonUtils.toFileMessage(getContent()); - - if (null != fileMessage.getUrl()) { - urls.add(fileMessage.getUrl()); - } - } else if (Message.MSGTYPE_VIDEO.equals(msgType)) { - VideoMessage videoMessage = JsonUtils.toVideoMessage(getContent()); - - if (null != videoMessage.getUrl()) { - urls.add(videoMessage.getUrl()); - } - if (null != videoMessage.getThumbnailUrl()) { - urls.add(videoMessage.getThumbnailUrl()); - } - } else if (Message.MSGTYPE_LOCATION.equals(msgType)) { - LocationMessage locationMessage = JsonUtils.toLocationMessage(getContent()); - - if (null != locationMessage.thumbnail_url) { - urls.add(locationMessage.thumbnail_url); - } - } - } else if (Event.EVENT_TYPE_STICKER.equals(getType())) { - StickerMessage stickerMessage = JsonUtils.toStickerMessage(getContent()); - - if (null != stickerMessage.getUrl()) { - urls.add(stickerMessage.getUrl()); - } - - if (null != stickerMessage.getThumbnailUrl()) { - urls.add(stickerMessage.getThumbnailUrl()); - } - } - - return urls; - } - - /** - * @return all the encrypted file infos defined in the event. - */ - public List getEncryptedFileInfos() { - List encryptedFileInfos = new ArrayList<>(); - - if (!isEncrypted()) { - // return empty array - return encryptedFileInfos; - } - - if (Event.EVENT_TYPE_MESSAGE.equals(getType())) { - String msgType = JsonUtils.getMessageMsgType(getContent()); - - if (Message.MSGTYPE_IMAGE.equals(msgType)) { - ImageMessage imageMessage = JsonUtils.toImageMessage(getContent()); - - if (null != imageMessage.file) { - encryptedFileInfos.add(imageMessage.file); - } - if (null != imageMessage.info && null != imageMessage.info.thumbnail_file) { - encryptedFileInfos.add(imageMessage.info.thumbnail_file); - } - } else if (Message.MSGTYPE_FILE.equals(msgType) || Message.MSGTYPE_AUDIO.equals(msgType)) { - FileMessage fileMessage = JsonUtils.toFileMessage(getContent()); - - if (null != fileMessage.file) { - encryptedFileInfos.add(fileMessage.file); - } - } else if (Message.MSGTYPE_VIDEO.equals(msgType)) { - VideoMessage videoMessage = JsonUtils.toVideoMessage(getContent()); - - if (null != videoMessage.file) { - encryptedFileInfos.add(videoMessage.file); - } - if (null != videoMessage.info && null != videoMessage.info.thumbnail_file) { - encryptedFileInfos.add(videoMessage.info.thumbnail_file); - } - } - } else if (Event.EVENT_TYPE_STICKER.equals(getType())) { - StickerMessage stickerMessage = JsonUtils.toStickerMessage(getContent()); - - if (null != stickerMessage.file) { - encryptedFileInfos.add(stickerMessage.file); - } - if (null != stickerMessage.info && null != stickerMessage.info.thumbnail_file) { - encryptedFileInfos.add(stickerMessage.info.thumbnail_file); - } - } - - return encryptedFileInfos; - } - - /** - * Tells if the current event is uploading a media. - * - * @param mediasCache the media cache - * @return true if the event is uploading a media. - */ - public boolean isUploadingMedias(MXMediasCache mediasCache) { - List urls = getMediaUrls(); - - for (String url : urls) { - if (mediasCache.getProgressValueForUploadId(url) >= 0) { - return true; - } - } - - return false; - } - - /** - * Tells if the current event is downloading a media. - * - * @param mediasCache the media cache - * @return true if the event is downloading a media. - */ - public boolean isDownloadingMedias(MXMediasCache mediasCache) { - List urls = getMediaUrls(); - - for (String url : urls) { - if (mediasCache.getProgressValueForDownloadId(mediasCache.downloadIdFromUrl(url)) >= 0) { - return true; - } - } - - return false; - } - - @Override - public String toString() { - // build the string by hand - String text = "{\n"; - - text += " \"age\" : " + age + ",\n"; - - text += " \"content\": {\n"; - - if (null != getWireContent()) { - if (getWireContent().isJsonArray()) { - for (JsonElement e : getWireContent().getAsJsonArray()) { - text += " " + e.toString() + ",\n"; - } - } else if (getWireContent().isJsonObject()) { - for (Map.Entry e : getWireContent().getAsJsonObject().entrySet()) { - text += " \"" + e.getKey() + "\": " + e.getValue().toString() + ",\n"; - } - } else { - text += getWireContent().toString(); - } - } - - text += " },\n"; - - text += " \"eventId\": \"" + eventId + "\",\n"; - text += " \"originServerTs\": " + originServerTs + ",\n"; - text += " \"roomId\": \"" + roomId + "\",\n"; - text += " \"type\": \"" + type + "\",\n"; - text += " \"userId\": \"" + userId + "\",\n"; - text += " \"sender\": \"" + sender + "\",\n"; - - text += "}"; - - text += "\n\n Sent state : "; - - if (mSentState == SentState.UNSENT) { - text += "UNSENT"; - } else if (mSentState == SentState.SENDING) { - text += "SENDING"; - } else if (mSentState == SentState.WAITING_RETRY) { - text += "WAITING_RETRY"; - } else if (mSentState == SentState.SENT) { - text += "SENT"; - } else if (mSentState == SentState.UNDELIVERED) { - text += "UNDELIVERED"; - } else if (mSentState == SentState.FAILED_UNKNOWN_DEVICES) { - text += "FAILED UNKNOWN DEVICES"; - } - - if (null != unsentException) { - text += "\n\n Exception reason: " + unsentException.getMessage() + "\n"; - } - - if (null != unsentMatrixError) { - text += "\n\n Matrix reason: " + unsentMatrixError.getLocalizedMessage() + "\n"; - } - - return text; - } - - @Override - public void readExternal(ObjectInput input) throws IOException, ClassNotFoundException { - if (input.readBoolean()) { - type = input.readUTF(); - } - - if (input.readBoolean()) { - contentAsString = input.readUTF(); - } - - if (input.readBoolean()) { - prev_content_as_string = input.readUTF(); - } - - if (input.readBoolean()) { - eventId = input.readUTF(); - } - - if (input.readBoolean()) { - roomId = input.readUTF(); - } - - if (input.readBoolean()) { - userId = input.readUTF(); - } - - if (input.readBoolean()) { - sender = input.readUTF(); - } - - originServerTs = input.readLong(); - - if (input.readBoolean()) { - age = input.readLong(); - } - - if (input.readBoolean()) { - stateKey = input.readUTF(); - } - - if (input.readBoolean()) { - unsigned = (UnsignedData) input.readObject(); - } - - if (input.readBoolean()) { - redacts = input.readUTF(); - } - - if (input.readBoolean()) { - invite_room_state = (List) input.readObject(); - } - - if (input.readBoolean()) { - unsentException = (Exception) input.readObject(); - } - - if (input.readBoolean()) { - unsentMatrixError = (MatrixError) input.readObject(); - } - - mSentState = (SentState) input.readObject(); - - if (input.readBoolean()) { - mToken = input.readUTF(); - } - - mIsInternalPaginationToken = input.readBoolean(); - - if (input.readBoolean()) { - mMatrixId = input.readUTF(); - } - - mTimeZoneRawOffset = input.readLong(); - } - - @Override - public void writeExternal(ObjectOutput output) throws IOException { - prepareSerialization(); - - output.writeBoolean(null != type); - if (null != type) { - output.writeUTF(type); - } - - output.writeBoolean(null != contentAsString); - if (null != contentAsString) { - output.writeUTF(contentAsString); - } - - output.writeBoolean(null != prev_content_as_string); - if (null != prev_content_as_string) { - output.writeUTF(prev_content_as_string); - } - - output.writeBoolean(null != eventId); - if (null != eventId) { - output.writeUTF(eventId); - } - - output.writeBoolean(null != roomId); - if (null != roomId) { - output.writeUTF(roomId); - } - - output.writeBoolean(null != userId); - if (null != userId) { - output.writeUTF(userId); - } - - output.writeBoolean(null != sender); - if (null != sender) { - output.writeUTF(sender); - } - - output.writeLong(originServerTs); - - output.writeBoolean(null != age); - if (null != age) { - output.writeLong(age); - } - - output.writeBoolean(null != stateKey); - if (null != stateKey) { - output.writeUTF(stateKey); - } - - output.writeBoolean(null != unsigned); - if (null != unsigned) { - output.writeObject(unsigned); - } - - output.writeBoolean(null != redacts); - if (null != redacts) { - output.writeUTF(redacts); - } - - output.writeBoolean(null != invite_room_state); - if (null != invite_room_state) { - output.writeObject(invite_room_state); - } - - output.writeBoolean(null != unsentException); - if (null != unsentException) { - output.writeObject(unsentException); - } - - output.writeBoolean(null != unsentMatrixError); - if (null != unsentMatrixError) { - output.writeObject(unsentMatrixError); - } - - output.writeObject(mSentState); - - output.writeBoolean(null != mToken); - if (null != mToken) { - output.writeUTF(mToken); - } - - output.writeBoolean(mIsInternalPaginationToken); - - output.writeBoolean(null != mMatrixId); - if (null != mMatrixId) { - output.writeUTF(mMatrixId); - } - - output.writeLong(mTimeZoneRawOffset); - } - - /** - * Init some internal fields to serialize the event. - */ - private void prepareSerialization() { - if ((null != content) && (null == contentAsString)) { - contentAsString = content.toString(); - } - - if ((null != getPrevContentAsJsonObject()) && (null == prev_content_as_string)) { - prev_content_as_string = getPrevContentAsJsonObject().toString(); - } - - if ((null != unsigned) && (null != unsigned.prev_content)) { - unsigned.prev_content = null; - } - } - - /** - * Deserialize the event. - */ - private void finalizeDeserialization() { - if ((null != contentAsString) && (null == content)) { - try { - content = new JsonParser().parse(contentAsString).getAsJsonObject(); - } catch (Exception e) { - Log.e(LOG_TAG, "finalizeDeserialization : contentAsString deserialization " + e.getMessage(), e); - contentAsString = null; - } - } - - if ((null != prev_content_as_string) && (null == prev_content)) { - try { - prev_content = new JsonParser().parse(prev_content_as_string).getAsJsonObject(); - } catch (Exception e) { - Log.e(LOG_TAG, "finalizeDeserialization : prev_content_as_string deserialization " + e.getMessage(), e); - prev_content_as_string = null; - } - } - } - - /** - * Filter a JsonObject to keep only the allowed keys. - * - * @param aContent the JsonObject to filter. - * @param allowedKeys the allowed keys list. - * @return the filtered JsonObject - */ - private static JsonObject filterInContentWithKeys(JsonObject aContent, List allowedKeys) { - // sanity check - if (null == aContent) { - return null; - } - - JsonObject filteredContent = new JsonObject(); - - // remove any key - if ((null == allowedKeys) || (0 == allowedKeys.size())) { - return new JsonObject(); - } - - Set> entries = aContent.entrySet(); - - if (null != entries) { - for (Map.Entry entry : entries) { - if (allowedKeys.indexOf(entry.getKey()) >= 0) { - filteredContent.add(entry.getKey(), entry.getValue()); - } - } - } - - return filteredContent; - } - - /** - * Prune the event which removes all keys we don't know about or think could potentially be dodgy. - * This is used when we "redact" an event. We want to remove all fields that the user has specified, - * but we do want to keep necessary information like type, state_key etc. - * - * @param redactionEvent the event which triggers this redaction - */ - public void prune(Event redactionEvent) { - // Filter in event by keeping only the following keys - List allowedKeys; - - // Add filtered content, allowed keys in content depends on the event type - if (TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_MEMBER, type)) { - allowedKeys = new ArrayList<>(Arrays.asList("membership")); - } else if (TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_CREATE, type)) { - allowedKeys = new ArrayList<>(Arrays.asList("creator")); - } else if (TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_JOIN_RULES, type)) { - allowedKeys = new ArrayList<>(Arrays.asList("join_rule")); - } else if (TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_POWER_LEVELS, type)) { - allowedKeys = new ArrayList<>(Arrays.asList("users", - "users_default", - "events", - "events_default", - "state_default", - "ban", - "kick", - "redact", - "invite")); - } else if (TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_ALIASES, type)) { - allowedKeys = new ArrayList<>(Arrays.asList("aliases")); - } else if (TextUtils.equals(Event.EVENT_TYPE_STATE_CANONICAL_ALIAS, type)) { - allowedKeys = new ArrayList<>(Arrays.asList("alias")); - } else if (TextUtils.equals(Event.EVENT_TYPE_FEEDBACK, type)) { - allowedKeys = new ArrayList<>(Arrays.asList("type", "target_event_id")); - } else if (TextUtils.equals(Event.EVENT_TYPE_MESSAGE_ENCRYPTED, type)) { - mClearEvent = null; - allowedKeys = null; - } else { - allowedKeys = null; - } - - content = filterInContentWithKeys(getContentAsJsonObject(), allowedKeys); - prev_content = filterInContentWithKeys(getPrevContentAsJsonObject(), allowedKeys); - - prev_content_as_string = null; - contentAsString = null; - - if (null != redactionEvent) { - if (null == unsigned) { - unsigned = new UnsignedData(); - } - - unsigned.redacted_because = new RedactedBecause(); - unsigned.redacted_because.type = redactionEvent.type; - unsigned.redacted_because.origin_server_ts = redactionEvent.originServerTs; - unsigned.redacted_because.sender = redactionEvent.sender; - unsigned.redacted_because.event_id = redactionEvent.eventId; - unsigned.redacted_because.unsigned = redactionEvent.unsigned; - unsigned.redacted_because.redacts = redactionEvent.redacts; - - unsigned.redacted_because.content = new RedactedContent(); - - JsonObject contentAsJson = getContentAsJsonObject(); - if ((null != contentAsJson) && contentAsJson.has("reason")) { - try { - unsigned.redacted_because.content.reason = contentAsJson.get("reason").getAsString(); - } catch (Exception e) { - Log.e(LOG_TAG, "unsigned.redacted_because.content.reason failed " + e.getMessage(), e); - } - - } - } - } - - //============================================================================================================== - // Crypto - //============================================================================================================== - - /** - * For encrypted events, the plaintext payload for the event. - * This is a small MXEvent instance with typically value for `type` and 'content' fields. - */ - private transient Event mClearEvent; - - /** - * Curve25519 key which we believe belongs to the sender of the event. - * See `senderKey` property. - */ - private transient String mSenderCurve25519Key; - - /** - * Ed25519 key which the sender of this event (for olm) or the creator of the megolm session (for megolm) claims to own. - * See `claimedEd25519Key` property. - */ - private transient String mClaimedEd25519Key; - - /** - * Curve25519 keys of devices involved in telling us about the senderCurve25519Key and claimedEd25519Key. - * See `forwardingCurve25519KeyChain` property. - */ - private transient List mForwardingCurve25519KeyChain = new ArrayList<>(); - - /** - * Decryption error - */ - private MXCryptoError mCryptoError; - - /** - * @return true if this event is encrypted. - */ - public boolean isEncrypted() { - return TextUtils.equals(getWireType(), EVENT_TYPE_MESSAGE_ENCRYPTED); - } - - /** - * Update the clear data on this event. - * This is used after decrypting an event; it should not be used by applications. - * It fires kMXEventDidDecryptNotification. - * - * @param decryptionResult the decryption result, including the plaintext and some key info. - */ - public void setClearData(@Nullable MXEventDecryptionResult decryptionResult) { - mClearEvent = null; - - if (null != decryptionResult) { - if (null != decryptionResult.mClearEvent) { - mClearEvent = JsonUtils.toEvent(decryptionResult.mClearEvent); - } - - if (null != mClearEvent) { - mClearEvent.mSenderCurve25519Key = decryptionResult.mSenderCurve25519Key; - mClearEvent.mClaimedEd25519Key = decryptionResult.mClaimedEd25519Key; - - if (null != decryptionResult.mForwardingCurve25519KeyChain) { - mClearEvent.mForwardingCurve25519KeyChain = decryptionResult.mForwardingCurve25519KeyChain; - } else { - mClearEvent.mForwardingCurve25519KeyChain = new ArrayList<>(); - } - - try { - // Add "m.relates_to" data from e2e event to the unencrypted event - if (getWireContent().getAsJsonObject().has("m.relates_to")) { - mClearEvent.getContentAsJsonObject() - .add("m.relates_to", getWireContent().getAsJsonObject().get("m.relates_to")); - } - } catch (Exception e) { - Log.e(LOG_TAG, "Unable to restore 'm.relates_to' the clear event", e); - } - } - - mCryptoError = null; - } - } - - /** - * @return The curve25519 key that sent this event. - */ - public String senderKey() { - if (null != mClearEvent) { - return mClearEvent.mSenderCurve25519Key; - } else { - return mSenderCurve25519Key; - } - } - - /** - * @return The additional keys the sender of this encrypted event claims to possess. - */ - public Map getKeysClaimed() { - Map res = new HashMap<>(); - - String claimedEd25519Key = (null != getClearEvent()) ? getClearEvent().mClaimedEd25519Key : mClaimedEd25519Key; - - if (null != claimedEd25519Key) { - res.put("ed25519", claimedEd25519Key); - } - - return res; - } - - /** - * @return the claimed Ed25519 key - */ - /*public String getClaimedEd25519Key() { - if (null != mClearEvent) { - return mClearEvent.mClaimedEd25519Key; - } else { - return mClaimedEd25519Key; - } - }*/ - - /** - * @return Get the curve25519 keys of the devices which were involved in telling us about the claimedEd25519Key and sender curve25519 key. - */ - /*public List getForwardingCurve25519KeyChain() { - List res = (null != mClearEvent) ? mClearEvent.mForwardingCurve25519KeyChain : mForwardingCurve25519KeyChain; - - if (null == res) { - res = new ArrayList<>(); - } - - return res; - }*/ - - /** - * @return the linked crypto error - */ - public MXCryptoError getCryptoError() { - return mCryptoError; - } - - /** - * Update the linked crypto error - * - * @param error the new crypto error. - */ - public void setCryptoError(MXCryptoError error) { - mCryptoError = error; - if (null != error) { - mClearEvent = null; - } - } - - /** - * @return the clear event - */ - public Event getClearEvent() { - return mClearEvent; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/EventContent.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/EventContent.java deleted file mode 100644 index ae0540d5..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/EventContent.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model; - -import im.vector.matrix.android.internal.legacy.rest.model.pid.RoomThirdPartyInvite; - -/** - * Class representing an event content - */ -public class EventContent implements java.io.Serializable { - /** - * The display name for this user, if any. - */ - public String displayname; - - /** - * The avatar URL for this user, if any. - */ - public String avatar_url; - - /** - * The membership state of the user. One of: ["invite", "join", "knock", "leave", "ban"] - */ - public String membership; - - /** - * the third party invite - */ - public RoomThirdPartyInvite third_party_invite; - - /* - * e2e encryption format - */ - public String algorithm; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/EventContext.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/EventContext.java deleted file mode 100644 index 8e8a4680..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/EventContext.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.rest.model; - -import java.util.List; - -/** - * represents the response to the /context request. - */ -public class EventContext { - - /** - * The event on which /context has been requested. - */ - public Event event; - - /** - * A token that can be used to paginate backwards with. - */ - public String start; - - /** - * A list of room events that happened just before the requested event. - * The order is anti-chronological. - */ - public List eventsBefore; - - /** - * A list of room events that happened just after the requested event. - * The order is chronological. - */ - public List eventsAfter; - - /** - * A token that can be used to paginate forwards with. - */ - public String end; - - /** - * The state of the room at the last event returned. - */ - public List state; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ForgetPasswordParams.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ForgetPasswordParams.java deleted file mode 100644 index f340681a..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ForgetPasswordParams.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model; - -/** - * The forget password params - */ -public class ForgetPasswordParams { - - /** - * The email address - **/ - public String email; - - /** - * Client-generated secret string used to protect this session - **/ - public String client_secret; - - /** - * Used to distinguish protocol level retries from requests to re-send the email. - **/ - public Integer send_attempt; - - /** - * The ID server to send the onward request to as a hostname with an appended colon and port number if the port is not the default. - **/ - public String id_server; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ForgetPasswordResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ForgetPasswordResponse.java deleted file mode 100644 index 46570b3c..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ForgetPasswordResponse.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model; - -/** - * The forget password response - */ -public class ForgetPasswordResponse { - - /** - * The session id - **/ - public String sid; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/HttpError.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/HttpError.java deleted file mode 100644 index baeec219..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/HttpError.java +++ /dev/null @@ -1,44 +0,0 @@ -package im.vector.matrix.android.internal.legacy.rest.model; - -public final class HttpError { - private final String errorBody; - private final int httpCode; - - public HttpError(String errorBody, int httpCode) { - this.errorBody = errorBody; - this.httpCode = httpCode; - } - - public String getErrorBody() { - return errorBody; - } - - public int getHttpCode() { - return httpCode; - } - - @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - HttpError httpError = (HttpError) o; - - if (httpCode != httpError.httpCode) return false; - return errorBody != null ? - errorBody.equals(httpError.errorBody) : - httpError.errorBody == null; - } - - @Override public int hashCode() { - int result = errorBody != null ? errorBody.hashCode() : 0; - result = 31 * result + httpCode; - return result; - } - - @Override public String toString() { - return "HttpError{" + - "errorBody='" + errorBody + '\'' + - ", httpCode=" + httpCode + - '}'; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/HttpException.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/HttpException.java deleted file mode 100644 index 957d49a9..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/HttpException.java +++ /dev/null @@ -1,14 +0,0 @@ -package im.vector.matrix.android.internal.legacy.rest.model; - -public class HttpException extends Exception { - - private final HttpError httpError; - - public HttpException(HttpError httpError) { - this.httpError = httpError; - } - - public HttpError getHttpError() { - return httpError; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/Invite.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/Invite.java deleted file mode 100644 index 9105ca7f..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/Invite.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model; - -/** - * subclass representing a search API response - */ -public class Invite implements java.io.Serializable { - /** - * A name which can be displayed to represent the user instead of their third party identifier. - */ - public String display_name; - - /** - * A block of content which has been signed, which servers can use to verify the event. Clients should ignore this. - */ - public Signed signed; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/MatrixError.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/MatrixError.java deleted file mode 100644 index ae7fd3e1..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/MatrixError.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model; - -import android.support.annotation.Nullable; -import android.text.TextUtils; - -import com.google.gson.annotations.SerializedName; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - -import okhttp3.MediaType; -import okhttp3.ResponseBody; - -/** - * Represents a standard error response. - */ -public class MatrixError implements java.io.Serializable { - public static final String FORBIDDEN = "M_FORBIDDEN"; - public static final String UNKNOWN = "M_UNKNOWN"; - public static final String UNKNOWN_TOKEN = "M_UNKNOWN_TOKEN"; - public static final String BAD_JSON = "M_BAD_JSON"; - public static final String NOT_JSON = "M_NOT_JSON"; - public static final String NOT_FOUND = "M_NOT_FOUND"; - public static final String LIMIT_EXCEEDED = "M_LIMIT_EXCEEDED"; - public static final String USER_IN_USE = "M_USER_IN_USE"; - public static final String ROOM_IN_USE = "M_ROOM_IN_USE"; - public static final String BAD_PAGINATION = "M_BAD_PAGINATION"; - public static final String UNAUTHORIZED = "M_UNAUTHORIZED"; - public static final String OLD_VERSION = "M_OLD_VERSION"; - public static final String UNRECOGNIZED = "M_UNRECOGNIZED"; - - public static final String LOGIN_EMAIL_URL_NOT_YET = "M_LOGIN_EMAIL_URL_NOT_YET"; - public static final String THREEPID_AUTH_FAILED = "M_THREEPID_AUTH_FAILED"; - // Error code returned by the server when no account matches the given 3pid - public static final String THREEPID_NOT_FOUND = "M_THREEPID_NOT_FOUND"; - public static final String THREEPID_IN_USE = "M_THREEPID_IN_USE"; - public static final String SERVER_NOT_TRUSTED = "M_SERVER_NOT_TRUSTED"; - public static final String TOO_LARGE = "M_TOO_LARGE"; - public static final String M_CONSENT_NOT_GIVEN = "M_CONSENT_NOT_GIVEN"; - public static final String RESOURCE_LIMIT_EXCEEDED = "M_RESOURCE_LIMIT_EXCEEDED"; - - // custom ones - public static final String NOT_SUPPORTED = "M_NOT_SUPPORTED"; - - // Possible value for "limit_type" - public static final String LIMIT_TYPE_MAU = "monthly_active_user"; - - // Define the configuration error codes. - // The others matrix errors are requests dedicated - // UNKNOWN_TOKEN : the access token is no more valid - // OLD_VERSION : the current SDK / application versions are too old and might trigger some unexpected errors. - public static final Set mConfigurationErrorCodes = new HashSet<>(Arrays.asList(UNKNOWN_TOKEN, OLD_VERSION)); - - public String errcode; - public String error; - public Integer retry_after_ms; - - @SerializedName("consent_uri") - public String consentUri; - - // RESOURCE_LIMIT_EXCEEDED data - @SerializedName("limit_type") - public String limitType; - @Nullable - @SerializedName("admin_contact") - public String adminUri; - - - // extracted from the error response - public Integer mStatus; - public String mReason; - public ResponseBody mErrorBody; - public String mErrorBodyAsString; - public MediaType mErrorBodyMimeType; - - /** - * Default creator - */ - public MatrixError() { - } - - /** - * Creator with error description - * - * @param anErrcode the error code. - * @param anError the error message. - */ - public MatrixError(String anErrcode, String anError) { - errcode = anErrcode; - error = anError; - } - - /** - * @return a localized error message. - */ - public String getLocalizedMessage() { - String localizedMessage = ""; - - if (!TextUtils.isEmpty(error)) { - localizedMessage = error; - } else if (!TextUtils.isEmpty(errcode)) { - localizedMessage = errcode; - } - - return localizedMessage; - } - - /** - * @return a error message. - */ - public String getMessage() { - return getLocalizedMessage(); - } - - /** - * @return true if the error code is a supported one - */ - public boolean isSupportedErrorCode() { - return MatrixError.FORBIDDEN.equals(errcode) - || MatrixError.UNKNOWN_TOKEN.equals(errcode) - || MatrixError.BAD_JSON.equals(errcode) - || MatrixError.NOT_JSON.equals(errcode) - || MatrixError.NOT_FOUND.equals(errcode) - || MatrixError.LIMIT_EXCEEDED.equals(errcode) - || MatrixError.USER_IN_USE.equals(errcode) - || MatrixError.ROOM_IN_USE.equals(errcode) - || MatrixError.TOO_LARGE.equals(errcode) - || MatrixError.BAD_PAGINATION.equals(errcode) - || MatrixError.OLD_VERSION.equals(errcode) - || MatrixError.UNRECOGNIZED.equals(errcode) - || MatrixError.RESOURCE_LIMIT_EXCEEDED.equals(errcode); - } - - /** - * Tells if a matrix error code is a configuration error code. - * - * @param matrixErrorCode the matrix error code - * @return true if it is one - */ - public static boolean isConfigurationErrorCode(String matrixErrorCode) { - return (null != matrixErrorCode) && mConfigurationErrorCodes.contains(matrixErrorCode); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/MediaScanPublicKeyResult.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/MediaScanPublicKeyResult.java deleted file mode 100644 index 14599399..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/MediaScanPublicKeyResult.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.rest.model; - -import com.google.gson.annotations.SerializedName; - -/** - * Class to contain the public key of the media scan server. - */ -public class MediaScanPublicKeyResult { - - @SerializedName("public_key") - public String mCurve25519PublicKey; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/MediaScanResult.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/MediaScanResult.java deleted file mode 100644 index 138e156c..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/MediaScanResult.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.rest.model; - -/** - * Class to contain the anti-virus scan result of a matrix content. - */ -public class MediaScanResult { - // If true, the script ran with an exit code of 0. Otherwise it ran with a non-zero exit code. - public boolean clean; - // Human-readable information about the result. - public String info; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/PowerLevels.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/PowerLevels.java deleted file mode 100644 index a2be2ee8..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/PowerLevels.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model; - -import android.text.TextUtils; - -import java.util.HashMap; -import java.util.Map; - -public class PowerLevels implements java.io.Serializable { - public int ban = 50; - public int kick = 50; - public int invite = 50; - public int redact = 50; - - public int events_default = 0; - public Map events = new HashMap<>(); - - public int users_default = 0; - public Map users = new HashMap<>(); - - public int state_default = 50; - - public Map notifications = new HashMap<>(); - - public PowerLevels deepCopy() { - PowerLevels copy = new PowerLevels(); - copy.ban = ban; - copy.kick = kick; - copy.invite = invite; - copy.redact = redact; - - copy.events_default = events_default; - copy.events = new HashMap<>(); - copy.events.putAll(events); - - copy.users_default = users_default; - copy.users = new HashMap<>(); - copy.users.putAll(users); - - copy.state_default = state_default; - - copy.notifications = new HashMap<>(notifications); - - return copy; - } - - /** - * Returns the user power level of a dedicated user Id - * - * @param userId the user id - * @return the power level - */ - public int getUserPowerLevel(String userId) { - // sanity check - if (!TextUtils.isEmpty(userId)) { - Integer powerLevel = users.get(userId); - return (powerLevel != null) ? powerLevel : users_default; - } - - return users_default; - } - - /** - * Updates the user power levels of a dedicated user id - * - * @param userId the user - * @param powerLevel the new power level - */ - public void setUserPowerLevel(String userId, int powerLevel) { - if (null != userId) { - users.put(userId, Integer.valueOf(powerLevel)); - } - } - - /** - * Tell if an user can send an event of type 'eventTypeString'. - * - * @param eventTypeString the event type (in Event.EVENT_TYPE_XXX values) - * @param userId the user id - * @return true if the user can send the event - */ - public boolean maySendEventOfType(String eventTypeString, String userId) { - if (!TextUtils.isEmpty(eventTypeString) && !TextUtils.isEmpty(userId)) { - return getUserPowerLevel(userId) >= minimumPowerLevelForSendingEventAsMessage(eventTypeString); - } - - return false; - } - - /** - * Tells if an user can send a room message. - * - * @param userId the user id - * @return true if the user can send a room message - */ - public boolean maySendMessage(String userId) { - return maySendEventOfType(Event.EVENT_TYPE_MESSAGE, userId); - } - - /** - * Helper to get the minimum power level the user must have to send an event of the given type - * as a message. - * - * @param eventTypeString the type of event (in Event.EVENT_TYPE_XXX values) - * @return the required minimum power level. - */ - public int minimumPowerLevelForSendingEventAsMessage(String eventTypeString) { - int minimumPowerLevel = events_default; - - if ((null != eventTypeString) && events.containsKey(eventTypeString)) { - minimumPowerLevel = events.get(eventTypeString); - } - - return minimumPowerLevel; - } - - /** - * Helper to get the minimum power level the user must have to send an event of the given type - * as a state event. - * - * @param eventTypeString the type of event (in Event.EVENT_TYPE_STATE_ values). - * @return the required minimum power level. - */ - public int minimumPowerLevelForSendingEventAsStateEvent(String eventTypeString) { - int minimumPowerLevel = state_default; - - if ((null != eventTypeString) && events.containsKey(eventTypeString)) { - minimumPowerLevel = events.get(eventTypeString); - } - - return minimumPowerLevel; - } - - - /** - * Get the notification level for a dedicated key. - * - * @param key the notification key - * @return the level - */ - public int notificationLevel(String key) { - if ((null != key) && notifications.containsKey(key)) { - Object valAsVoid = notifications.get(key); - - // the first implementation was a string value - if (valAsVoid instanceof String) { - return Integer.parseInt((String) valAsVoid); - } else { - return (int) valAsVoid; - } - } - - return 50; - } -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/PushersResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/PushersResponse.java deleted file mode 100644 index a3a9d28f..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/PushersResponse.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model; - -import im.vector.matrix.android.internal.legacy.data.Pusher; - -import java.util.List; - -/** - * Class representing the pushers GET response - */ -public class PushersResponse { - public List pushers; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ReceiptData.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ReceiptData.java deleted file mode 100644 index 89372347..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ReceiptData.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model; - -import im.vector.matrix.android.internal.legacy.interfaces.DatedObject; - -public class ReceiptData implements java.io.Serializable, DatedObject { - - // the user id - public String userId; - - // The event id. - public String eventId; - - // The timestamp in ms since Epoch generated by the origin homeserver when it receives the event from the client. - public long originServerTs; - - public ReceiptData(String anUserId, String anEventId, long aTs) { - userId = anUserId; - eventId = anEventId; - originServerTs = aTs; - } - - @Override - public long getDate() { - return originServerTs; - } -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RedactedBecause.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RedactedBecause.java deleted file mode 100644 index c81881da..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RedactedBecause.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model; - -/** - * Redacted information - */ -public class RedactedBecause implements java.io.Serializable { - - // should be m.room.redaction" - public String type; - - // - public long origin_server_ts; - - // the redacted sender - public String sender; - - // the events Id - public String event_id; - - // unsigned - public UnsignedData unsigned; - - // - public String redacts; - - // should defined the reason - public RedactedContent content; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RedactedContent.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RedactedContent.java deleted file mode 100644 index 06636683..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RedactedContent.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model; - -/** - * Redacted information - */ -public class RedactedContent implements java.io.Serializable { - - // the redaction reason - public String reason; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ReportContentParams.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ReportContentParams.java deleted file mode 100644 index fc6ecc78..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ReportContentParams.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model; - -import java.util.List; - -/** - * Parameters to report an event content - */ -public class ReportContentParams { - - // The event range from -100 “most offensive” to 0 “inoffensive”. - public int score; - - // the report reason - public String reason; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RequestEmailValidationParams.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RequestEmailValidationParams.java deleted file mode 100755 index 8c4c68a4..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RequestEmailValidationParams.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.rest.model; - -/** - * Parameters to request a validation token for an email - */ -public class RequestEmailValidationParams { - - // the email address - public String email; - - // the client secret key - public String clientSecret; - - // the attempt count - public Integer sendAttempt; - - // the server id - public String id_server; - - // the nextlink (given if it is a registration process) - public String next_link; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RequestEmailValidationResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RequestEmailValidationResponse.java deleted file mode 100755 index 8fd3b9ec..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RequestEmailValidationResponse.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model; - -/** - * Response to a request an email validation post - */ -public class RequestEmailValidationResponse { - - // the client secret key - public String clientSecret; - - // the email address - public String email; - - // the attempt count - public Integer sendAttempt; - - // the email sid - public String sid; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RequestPhoneNumberValidationParams.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RequestPhoneNumberValidationParams.java deleted file mode 100755 index b62fbaa6..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RequestPhoneNumberValidationParams.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.rest.model; - -/** - * Parameters to request a validation token for a phone number - */ -public class RequestPhoneNumberValidationParams { - - // the country - public String country; - - // the phone number - public String phone_number; - - // the client secret key - public String clientSecret; - - // the attempt count - public Integer sendAttempt; - - // the server id - public String id_server; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RequestPhoneNumberValidationResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RequestPhoneNumberValidationResponse.java deleted file mode 100755 index c11813e5..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RequestPhoneNumberValidationResponse.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.rest.model; - -/** - * Response to a request an phone number validation request - */ -public class RequestPhoneNumberValidationResponse { - - // the client secret key - public String clientSecret; - - // the attempt count - public Integer sendAttempt; - - // the sid - public String sid; - - // the msisdn - public String msisdn; - - // phone number international format - public String intl_fmt; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RoomAliasDescription.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RoomAliasDescription.java deleted file mode 100644 index f034cb2e..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RoomAliasDescription.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.rest.model; - -import java.util.List; - -/** - * Class representing a room alias - */ -public class RoomAliasDescription { - /** - * The room ID for this alias. - */ - public String room_id; - - /** - * A list of servers that are aware of this room ID. - */ - public List servers; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RoomCreateContent.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RoomCreateContent.java deleted file mode 100644 index 3d4e2fe6..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RoomCreateContent.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.rest.model; - - -import com.google.gson.annotations.SerializedName; - -import java.io.Serializable; - -/** - * Content of a m.room.create type event - */ -public class RoomCreateContent implements Serializable { - - public String creator; - public Predecessor predecessor; - - public RoomCreateContent deepCopy() { - final RoomCreateContent copy = new RoomCreateContent(); - copy.creator = creator; - copy.predecessor = predecessor != null ? predecessor.deepCopy() : null; - return copy; - } - - public boolean hasPredecessor() { - return predecessor != null; - } - - /** - * A link to an old room in case of room versioning - */ - public static class Predecessor implements Serializable { - - @SerializedName("room_id") - public String roomId; - - @SerializedName("event_id") - public String eventId; - - public Predecessor deepCopy() { - final Predecessor copy = new Predecessor(); - copy.roomId = roomId; - copy.eventId = eventId; - return copy; - } - } - - -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RoomDirectoryVisibility.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RoomDirectoryVisibility.java deleted file mode 100644 index 24d76067..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RoomDirectoryVisibility.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.rest.model; - -public class RoomDirectoryVisibility { - public static final String DIRECTORY_VISIBILITY_PRIVATE = "private"; - public static final String DIRECTORY_VISIBILITY_PUBLIC = "public"; - - public String visibility; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RoomMember.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RoomMember.java deleted file mode 100644 index e797b831..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RoomMember.java +++ /dev/null @@ -1,349 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model; - -import android.text.TextUtils; - -import com.google.gson.annotations.SerializedName; - -import im.vector.matrix.android.internal.legacy.util.ContentManager; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.io.Externalizable; -import java.io.IOException; -import java.io.ObjectInput; -import java.io.ObjectOutput; -import java.util.Comparator; - -/** - * Class representing a room member: a user with membership information. - */ -public class RoomMember implements Externalizable { - private static final String LOG_TAG = RoomMember.class.getSimpleName(); - - public static final String MEMBERSHIP_JOIN = "join"; - public static final String MEMBERSHIP_INVITE = "invite"; - public static final String MEMBERSHIP_LEAVE = "leave"; - public static final String MEMBERSHIP_BAN = "ban"; - - // not supported by the server sync response by computed from the room state events - public static final String MEMBERSHIP_KICK = "kick"; - - public String displayname; - public String avatarUrl; - public String membership; - public Invite thirdPartyInvite; - - // tells that the inviter starts a direct chat room - @SerializedName("is_direct") - public Boolean isDirect; - - private String userId = null; - // timestamp of the event which has created this member - private long mOriginServerTs = -1; - - // the event used to build the room member - private String mOriginalEventId = null; - - // kick / ban reason - public String reason; - // user which banned or kicked this member - public String mSender; - - @Override - public void readExternal(ObjectInput input) throws IOException, ClassNotFoundException { - if (input.readBoolean()) { - displayname = input.readUTF(); - } - - if (input.readBoolean()) { - avatarUrl = input.readUTF(); - } - - if (input.readBoolean()) { - membership = input.readUTF(); - } - - if (input.readBoolean()) { - thirdPartyInvite = (Invite) input.readObject(); - } - - if (input.readBoolean()) { - isDirect = input.readBoolean(); - } - - if (input.readBoolean()) { - userId = input.readUTF(); - } - - mOriginServerTs = input.readLong(); - - if (input.readBoolean()) { - mOriginalEventId = input.readUTF(); - } - - if (input.readBoolean()) { - reason = input.readUTF(); - } - - if (input.readBoolean()) { - mSender = input.readUTF(); - } - } - - @Override - public void writeExternal(ObjectOutput output) throws IOException { - output.writeBoolean(null != displayname); - if (null != displayname) { - output.writeUTF(displayname); - } - - output.writeBoolean(null != avatarUrl); - if (null != avatarUrl) { - output.writeUTF(avatarUrl); - } - - output.writeBoolean(null != membership); - if (null != membership) { - output.writeUTF(membership); - } - - output.writeBoolean(null != thirdPartyInvite); - if (null != thirdPartyInvite) { - output.writeObject(thirdPartyInvite); - } - - output.writeBoolean(null != isDirect); - if (null != isDirect) { - output.writeBoolean(isDirect); - } - - output.writeBoolean(null != userId); - if (null != userId) { - output.writeUTF(userId); - } - - output.writeLong(mOriginServerTs); - - output.writeBoolean(null != mOriginalEventId); - if (null != mOriginalEventId) { - output.writeUTF(mOriginalEventId); - } - - output.writeBoolean(null != reason); - if (null != reason) { - output.writeUTF(reason); - } - - output.writeBoolean(null != mSender); - if (null != mSender) { - output.writeUTF(mSender); - } - } - - public String getUserId() { - return userId; - } - - public void setUserId(String userId) { - this.userId = userId; - } - - public void setOriginServerTs(long aTs) { - mOriginServerTs = aTs; - } - - public long getOriginServerTs() { - return mOriginServerTs; - } - - public void setOriginalEventId(String eventId) { - mOriginalEventId = eventId; - } - - public String getOriginalEventId() { - return mOriginalEventId; - } - - public String getAvatarUrl() { - // allow only url which starts with mxc:// - if ((null != avatarUrl) && !avatarUrl.toLowerCase().startsWith(ContentManager.MATRIX_CONTENT_URI_SCHEME)) { - Log.e(LOG_TAG, "## getAvatarUrl() : the member " + userId + " has an invalid avatar url " + avatarUrl); - return null; - } - - return avatarUrl; - } - - public void setAvatarUrl(String anAvatarUrl) { - avatarUrl = anAvatarUrl; - } - - public String getThirdPartyInviteToken() { - if ((null != thirdPartyInvite) && (null != thirdPartyInvite.signed)) { - return thirdPartyInvite.signed.token; - } - - return null; - } - - // Comparator to order members alphabetically - public static Comparator alphaComparator = new Comparator() { - @Override - public int compare(RoomMember member1, RoomMember member2) { - String lhs = member1.getName(); - String rhs = member2.getName(); - - if (lhs == null) { - return -1; - } else if (rhs == null) { - return 1; - } - if (lhs.startsWith("@")) { - lhs = lhs.substring(1); - } - if (rhs.startsWith("@")) { - rhs = rhs.substring(1); - } - return String.CASE_INSENSITIVE_ORDER.compare(lhs, rhs); - } - }; - - /** - * Test if a room member fields matches with a pattern. - * The check is done with the displayname and the userId. - * - * @param aPattern the pattern to search. - * @return true if it matches. - */ - public boolean matchWithPattern(String aPattern) { - if (TextUtils.isEmpty(aPattern) || TextUtils.isEmpty(aPattern.trim())) { - return false; - } - - boolean res = false; - - if (!TextUtils.isEmpty(displayname)) { - res = (displayname.toLowerCase().indexOf(aPattern) >= 0); - } - - if (!res && !TextUtils.isEmpty(userId)) { - res = (userId.toLowerCase().indexOf(aPattern) >= 0); - } - - return res; - } - - /** - * Test if a room member matches with a reg ex. - * The check is done with the displayname and the userId. - * - * @param aRegEx the reg ex - * @return true if it matches. - */ - public boolean matchWithRegEx(String aRegEx) { - if (TextUtils.isEmpty(aRegEx)) { - return false; - } - - boolean res = false; - - if (!TextUtils.isEmpty(displayname)) { - res = displayname.matches(aRegEx); - } - - if (!res && !TextUtils.isEmpty(userId)) { - res = userId.matches(aRegEx); - } - - return res; - } - - /** - * Compare two members. - * The members are equals if each field have the same value. - * - * @param otherMember the member to compare. - * @return true if they define the same member. - */ - public boolean equals(RoomMember otherMember) { - // compare to null - if (null == otherMember) { - return false; - } - - // compare display name - boolean isEqual = TextUtils.equals(displayname, otherMember.displayname); - - if (isEqual) { - isEqual = TextUtils.equals(avatarUrl, otherMember.avatarUrl); - } - - if (isEqual) { - isEqual = TextUtils.equals(membership, otherMember.membership); - } - - if (isEqual) { - isEqual = TextUtils.equals(userId, otherMember.userId); - } - - return isEqual; - } - - public String getName() { - if (displayname != null) { - return displayname; - } - if (userId != null) { - return userId; - } - return null; - } - - /** - * Prune the room member data as we would have done with its original state event. - */ - public void prune() { - // Redact redactable data - displayname = null; - avatarUrl = null; - reason = null; - - // Note: if we had access to the original event content, we should store - // the `redacted_because` of the redaction event in it. - } - - public RoomMember deepCopy() { - RoomMember copy = new RoomMember(); - copy.displayname = displayname; - copy.avatarUrl = avatarUrl; - copy.membership = membership; - copy.userId = userId; - copy.mOriginalEventId = mOriginalEventId; - copy.mSender = mSender; - copy.reason = reason; - return copy; - } - - /** - * @return true if the user has been banned or kicked - */ - public boolean kickedOrBanned() { - return TextUtils.equals(membership, MEMBERSHIP_KICK) || TextUtils.equals(membership, MEMBERSHIP_BAN); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RoomPinnedEventsContent.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RoomPinnedEventsContent.java deleted file mode 100644 index f081408d..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RoomPinnedEventsContent.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.rest.model; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -/** - * Content of a m.room.pinned_events type event - */ -public class RoomPinnedEventsContent implements Serializable { - - // List of eventIds of pinned events - public List pinned; - - public RoomPinnedEventsContent deepCopy() { - final RoomPinnedEventsContent copy = new RoomPinnedEventsContent(); - if (pinned == null) { - copy.pinned = null; - } else { - copy.pinned = new ArrayList<>(pinned); - } - return copy; - } - -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RoomTags.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RoomTags.java deleted file mode 100644 index f3774cee..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RoomTags.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model; - - -import java.util.Map; - -public class RoomTags implements java.io.Serializable { - public Map> tags; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RoomTombstoneContent.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RoomTombstoneContent.java deleted file mode 100644 index 84c720f1..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/RoomTombstoneContent.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.rest.model; - - -import com.google.gson.annotations.SerializedName; - -import java.io.Serializable; - -/** - * Class to contains Tombstone information - */ -public class RoomTombstoneContent implements Serializable { - - public String body; - - @SerializedName("replacement_room") - public String replacementRoom; - - public RoomTombstoneContent deepCopy() { - final RoomTombstoneContent copy = new RoomTombstoneContent(); - copy.body = body; - copy.replacementRoom = replacementRoom; - return copy; - } - -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ServerNoticeUsageLimitContent.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ServerNoticeUsageLimitContent.java deleted file mode 100644 index 5ad436fd..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ServerNoticeUsageLimitContent.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.rest.model; - -import com.google.gson.annotations.SerializedName; - -/** - * Content of a m.server_notice.usage_limit_reached type event - */ -public class ServerNoticeUsageLimitContent { - - private static final String EVENT_TYPE_SERVER_NOTICE_USAGE_LIMIT = "m.server_notice.usage_limit_reached"; - - // The kind of user limit, generally is monthly_active_user - public String limit; - @SerializedName("admin_contact") - public String adminUri; - @SerializedName("server_notice_type") - public String type; - - public boolean isServerNoticeUsageLimit() { - return EVENT_TYPE_SERVER_NOTICE_USAGE_LIMIT.equals(type); - } - -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/Signed.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/Signed.java deleted file mode 100644 index c4faf8d7..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/Signed.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model; - -/** - * subclass representing a search API response - */ -public class Signed implements java.io.Serializable { - /** - * The token property of the containing third_party_invite object. - */ - public String token; - - /** - * A single signature from the verifying server, in the format specified by the Signing Events section of the server-server API. - */ - public Object signatures; - - /** - * The invited matrix user ID. Must be equal to the user_id property of the event. - */ - public String mxid; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/StateEvent.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/StateEvent.java deleted file mode 100644 index 71b6d0e7..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/StateEvent.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.rest.model; - -import com.google.gson.annotations.SerializedName; - -import java.util.List; - -/** - * Class representing a state event content - * Usually, only one field is not null, depending of the type of the Event. - */ -public class StateEvent { - public String name; - - public String topic; - - @SerializedName("join_rule") - public String joinRule; - - @SerializedName("guest_access") - public String guestAccess; - - @SerializedName("alias") - public String canonicalAlias; - - public List aliases; - - public String algorithm; - - @SerializedName("history_visibility") - public String historyVisibility; - - public String url; - - public List groups; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ThreePidCreds.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ThreePidCreds.java deleted file mode 100755 index 8c4ecabb..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/ThreePidCreds.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model; - -/** - * 3 pid getCredentials - */ -public class ThreePidCreds { - - // the identity server URL (without the http://) - public String id_server; - - // the 3 pids sid - public String sid; - - // a secret key - public String client_secret; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/TokensChunkEvents.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/TokensChunkEvents.java deleted file mode 100644 index a65f579a..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/TokensChunkEvents.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.rest.model; - -import com.google.gson.annotations.SerializedName; - -import java.util.List; - -public class TokensChunkEvents extends TokensChunkResponse { - - // With LazyLoading, we can have state events here - @SerializedName("state") - public List stateEvents; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/TokensChunkResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/TokensChunkResponse.java deleted file mode 100644 index 849dab73..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/TokensChunkResponse.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model; - -/** - * Class representing an API response with start and end tokens and a generically-typed chunk. - */ -public class TokensChunkResponse extends ChunkResponse { - public String start; - public String end; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/Typing.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/Typing.java deleted file mode 100644 index 5dd7b970..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/Typing.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2015 OpenMarket 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.matrix.android.internal.legacy.rest.model; - -/** - * Class to contain a banned user and the reason they were banned. - */ -public class Typing { - public boolean typing; - public int timeout; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/URLPreview.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/URLPreview.java deleted file mode 100644 index a4686c90..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/URLPreview.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.rest.model; - -import android.text.TextUtils; - -import im.vector.matrix.android.internal.legacy.util.JsonUtils; - -import java.util.Map; - -/** - * Class representing an URL preview. - */ -public class URLPreview implements java.io.Serializable { - - private static final String OG_DESCRIPTION = "og:description"; - private static final String OG_TITLE = "og:title"; - private static final String OG_TYPE = "og:type"; - - private static final String OG_SITE_NAME = "og:site_name"; - private static final String OG_URL = "og:url"; - - private static final String OG_IMAGE = "og:image"; - private static final String OG_IMAGE_SIZE = "matrix:image:size"; - private static final String OG_IMAGE_TYPE = "og:image:type"; - private static final String OG_IMAGE_WIDTH = "og:image:width"; - private static final String OG_IMAGE_HEIGHT = "og:image:height"; - - /** - * Global information - */ - private final String mDescription; - private final String mTitle; - private final String mType; - - private final String mSiteName; - private final String mRequestedURL; - - /** - * Image information - */ - private final String mThumbnailURL; - private final String mThumbnailMimeType; - - private boolean mIsDismissed; - - /** - * Constructor - * - * @param map the constructor parameters - * @param url the original url, will be used if the map does not contain OG_URL field - */ - public URLPreview(Map map, String url) { - mDescription = JsonUtils.getAsString(map, OG_DESCRIPTION); - mTitle = JsonUtils.getAsString(map, OG_TITLE); - mType = JsonUtils.getAsString(map, OG_TYPE); - - mSiteName = JsonUtils.getAsString(map, OG_SITE_NAME); - - String requestedUrl = JsonUtils.getAsString(map, OG_URL); - - if (TextUtils.isEmpty(requestedUrl)) { - // Fallback: use url - mRequestedURL = url; - } else { - mRequestedURL = requestedUrl; - } - - mThumbnailURL = JsonUtils.getAsString(map, OG_IMAGE); - mThumbnailMimeType = JsonUtils.getAsString(map, OG_IMAGE_TYPE); - } - - - public String getDescription() { - return mDescription; - } - - public String getTitle() { - return mTitle; - } - - public String getType() { - return mType; - } - - public String getSiteName() { - return mSiteName; - } - - public String getRequestedURL() { - return mRequestedURL; - } - - public String getThumbnailURL() { - return mThumbnailURL; - } - - public String getThumbnailMimeType() { - return mThumbnailMimeType; - } - - public boolean IsDismissed() { - return mIsDismissed; - } - - public void setIsDismissed(boolean isDismissed) { - mIsDismissed = isDismissed; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/UnsignedData.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/UnsignedData.java deleted file mode 100644 index 7ebcc439..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/UnsignedData.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model; - -import com.google.gson.JsonElement; - -/** - * Contains optional extra information about the event. - */ -public class UnsignedData implements java.io.Serializable { - - /** - * The time in milliseconds that has elapsed since the event was sent - */ - public Long age; - - /** - * The reason this event was redacted, if it was redacted - */ - public RedactedBecause redacted_because; - - /** - * The client-supplied transaction ID, if the client being given the event is the same one which sent it. - */ - public String transaction_id; - - /** - * The previous event content (room member information only) - */ - public transient JsonElement prev_content; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/User.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/User.java deleted file mode 100644 index c1ee93e2..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/User.java +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model; - -import android.text.TextUtils; - -import im.vector.matrix.android.internal.legacy.MXDataHandler; -import im.vector.matrix.android.internal.legacy.listeners.IMXEventListener; -import im.vector.matrix.android.internal.legacy.listeners.MXEventListener; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Class representing a user. - */ -public class User implements java.io.Serializable { - private static final long serialVersionUID = 5234056937639712713L; - - // the user presence values - public static final String PRESENCE_ONLINE = "online"; - public static final String PRESENCE_UNAVAILABLE = "unavailable"; - public static final String PRESENCE_OFFLINE = "offline"; - public static final String PRESENCE_FREE_FOR_CHAT = "free_for_chat"; - public static final String PRESENCE_HIDDEN = "hidden"; - - // user fields provided by the server - public String user_id; - public String displayname; - public String avatar_url; - public String presence; - public Boolean currently_active; - public Long lastActiveAgo; - public String statusMsg; - - // tell if the information has been refreshed - private transient boolean mIsPresenceRefreshed; - - // Used to provide a more realistic last active time: - // the last active ago time provided by the server + the time that has gone by since - private long mLastPresenceTs; - - // Map to keep track of the listeners the client adds vs. the ones we actually register to the global data handler. - // This is needed to find the right one when removing the listener. - private transient Map mEventListeners = new HashMap<>(); - - // data handler - protected transient MXDataHandler mDataHandler; - - // events listeners list - private transient List mPendingListeners = new ArrayList<>(); - - // hash key to store the user in the file system; - private Integer mStorageHashKey = null; - - // The user data can have been retrieved by a room member - // The data can be partially invalid until a presence is received - private boolean mIsRetrievedFromRoomMember = false; - - // avatar URLs setter / getter - public String getAvatarUrl() { - return avatar_url; - } - - public void setAvatarUrl(String newAvatarUrl) { - avatar_url = newAvatarUrl; - } - - /** - * Tells if this user has been created from a room member event - * - * @return true if this user has been created from a room member event - */ - public boolean isRetrievedFromRoomMember() { - return mIsRetrievedFromRoomMember; - } - - /** - * Set that this user has been created from a room member. - */ - public void setRetrievedFromRoomMember() { - mIsRetrievedFromRoomMember = true; - } - - /** - * Check if mEventListeners has been initialized before providing it. - * The users are now serialized and the transient fields are not initialized. - * - * @return the events listener - */ - private Map getEventListeners() { - if (null == mEventListeners) { - mEventListeners = new HashMap<>(); - } - - return mEventListeners; - } - - /** - * Check if mPendingListeners has been initialized before providing it. - * The users are now serialized and the transient fields are not initialized. - * - * @return the pending listener - */ - private List getPendingListeners() { - if (null == mPendingListeners) { - mPendingListeners = new ArrayList<>(); - } - - return mPendingListeners; - } - - /** - * @return the user hash key - */ - public int getStorageHashKey() { - if (null == mStorageHashKey) { - mStorageHashKey = Math.abs(user_id.hashCode() % 100); - } - - return mStorageHashKey; - } - - /** - * @return true if the presence should be refreshed - */ - public boolean isPresenceObsolete() { - return !mIsPresenceRefreshed || (null == presence); - } - - /** - * Clone an user into this instance - * - * @param user the user to clone. - */ - protected void clone(User user) { - if (user != null) { - user_id = user.user_id; - displayname = user.displayname; - avatar_url = user.avatar_url; - presence = user.presence; - currently_active = user.currently_active; - lastActiveAgo = user.lastActiveAgo; - statusMsg = user.statusMsg; - - mIsPresenceRefreshed = user.mIsPresenceRefreshed; - mLastPresenceTs = user.mLastPresenceTs; - - mEventListeners = new HashMap<>(user.getEventListeners()); - mDataHandler = user.mDataHandler; - - mPendingListeners = user.getPendingListeners(); - } - } - - /** - * Create a deep copy of the current user. - * - * @return a deep copy of the current object - */ - public User deepCopy() { - User copy = new User(); - copy.clone(this); - return copy; - } - - /** - * Tells if an user is active - * - * @return true if the user is active - */ - public boolean isActive() { - return TextUtils.equals(presence, PRESENCE_ONLINE) || ((null != currently_active) && currently_active); - } - - /** - * Set the latest presence event time. - * - * @param ts the timestamp. - */ - public void setLatestPresenceTs(long ts) { - mIsPresenceRefreshed = true; - mLastPresenceTs = ts; - } - - /** - * @return the timestamp of the latest presence event. - */ - public long getLatestPresenceTs() { - return mLastPresenceTs; - } - - /** - * Get the user's last active ago time by adding the one given by the server and the time since elapsed. - * - * @return how long ago the user was last active (in ms) - */ - public long getAbsoluteLastActiveAgo() { - // sanity check - if (null == lastActiveAgo) { - return 0; - } else { - return System.currentTimeMillis() - (mLastPresenceTs - lastActiveAgo); - } - } - - /** - * Set the event listener to send back events to. This is typically the DataHandler for dispatching the events to listeners. - * - * @param dataHandler should be the main data handler for dispatching back events to registered listeners. - */ - public void setDataHandler(MXDataHandler dataHandler) { - mDataHandler = dataHandler; - - for (IMXEventListener listener : getPendingListeners()) { - mDataHandler.addListener(listener); - } - } - - /** - * Add an event listener to this room. Only events relative to the room will come down. - * - * @param eventListener the event listener to add - */ - public void addEventListener(final IMXEventListener eventListener) { - // Create a global listener that we'll add to the data handler - IMXEventListener globalListener = new MXEventListener() { - @Override - public void onPresenceUpdate(Event event, User user) { - // Only pass event through for this user - if (user.user_id.equals(user_id)) { - eventListener.onPresenceUpdate(event, user); - } - } - }; - getEventListeners().put(eventListener, globalListener); - - // the handler could be set later - if (null != mDataHandler) { - mDataHandler.addListener(globalListener); - } else { - getPendingListeners().add(globalListener); - } - } - - /** - * Remove an event listener. - * - * @param eventListener the event listener to remove - */ - public void removeEventListener(IMXEventListener eventListener) { - - if (null != mDataHandler) { - mDataHandler.removeListener(getEventListeners().get(eventListener)); - } else { - getPendingListeners().remove(getEventListeners().get(eventListener)); - } - - getEventListeners().remove(eventListener); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/Versions.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/Versions.java deleted file mode 100644 index 8d54ffe3..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/Versions.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.rest.model; - -import com.google.gson.annotations.SerializedName; - -import java.util.List; -import java.util.Map; - -/** - * Model for https://matrix.org/docs/spec/client_server/r0.3.0.html#get-matrix-client-versions - *

- * Ex: {"unstable_features": {"m.lazy_load_members": true}, "versions": ["r0.0.1", "r0.1.0", "r0.2.0", "r0.3.0"]} - */ -public class Versions { - - @SerializedName("versions") - public List supportedVersions; - - @SerializedName("unstable_features") - public Map unstableFeatures; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/BingRule.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/BingRule.java deleted file mode 100644 index a080285c..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/BingRule.java +++ /dev/null @@ -1,361 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.bingrules; - -import android.text.TextUtils; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.annotations.SerializedName; - -import im.vector.matrix.android.internal.legacy.util.JsonUtils; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class BingRule { - private static final String LOG_TAG = BingRule.class.getSimpleName(); - - public static final String RULE_ID_DISABLE_ALL = ".m.rule.master"; - public static final String RULE_ID_CONTAIN_USER_NAME = ".m.rule.contains_user_name"; - public static final String RULE_ID_CONTAIN_DISPLAY_NAME = ".m.rule.contains_display_name"; - public static final String RULE_ID_ONE_TO_ONE_ROOM = ".m.rule.room_one_to_one"; - public static final String RULE_ID_INVITE_ME = ".m.rule.invite_for_me"; - public static final String RULE_ID_PEOPLE_JOIN_LEAVE = ".m.rule.member_event"; - public static final String RULE_ID_CALL = ".m.rule.call"; - public static final String RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS = ".m.rule.suppress_notices"; - public static final String RULE_ID_ALL_OTHER_MESSAGES_ROOMS = ".m.rule.message"; - public static final String RULE_ID_FALLBACK = ".m.rule.fallback"; - - public static final String ACTION_NOTIFY = "notify"; - public static final String ACTION_DONT_NOTIFY = "dont_notify"; - public static final String ACTION_COALESCE = "coalesce"; - - public static final String ACTION_SET_TWEAK_SOUND_VALUE = "sound"; - public static final String ACTION_SET_TWEAK_HIGHLIGHT_VALUE = "highlight"; - - public static final String ACTION_PARAMETER_SET_TWEAK = "set_tweak"; - public static final String ACTION_PARAMETER_VALUE = "value"; - - public static final String ACTION_VALUE_DEFAULT = "default"; - public static final String ACTION_VALUE_RING = "ring"; - - public static final String KIND_OVERRIDE = "override"; - public static final String KIND_CONTENT = "content"; - public static final String KIND_ROOM = "room"; - public static final String KIND_SENDER = "sender"; - public static final String KIND_UNDERRIDE = "underride"; - - public String ruleId = null; - public List conditions = null; - // Object is either String or Map - public List actions = null; - @SerializedName("default") - public boolean isDefault = false; - - @SerializedName("enabled") - public boolean isEnabled = true; - - public String kind = null; - - public BingRule(boolean isDefaultValue) { - isDefault = isDefaultValue; - } - - public BingRule() { - isDefault = false; - } - - @Override - public String toString() { - return "BingRule{" + - "ruleId='" + ruleId + '\'' + - ", conditions=" + conditions + - ", actions=" + actions + - ", isDefault=" + isDefault + - ", isEnabled=" + isEnabled + - ", kind='" + kind + '\'' + - '}'; - } - - /** - * Convert BingRule to a JsonElement. - * It seems that "conditions" name triggers conversion issues. - * - * @return the JsonElement - */ - public JsonElement toJsonElement() { - JsonObject jsonObject = JsonUtils.getGson(false).toJsonTree(this).getAsJsonObject(); - - if (null != conditions) { - jsonObject.add("conditions", JsonUtils.getGson(false).toJsonTree(conditions)); - } - - return jsonObject; - } - - /** - * Bing rule creator - * - * @param ruleKind the rule kind - * @param aPattern the pattern to check the condition - * @param notify true to notify - * @param highlight true to highlight - * @param sound true to play sound - */ - public BingRule(String ruleKind, String aPattern, Boolean notify, Boolean highlight, boolean sound) { - // - ruleId = aPattern; - isEnabled = true; - isDefault = false; - kind = ruleKind; - conditions = null; - - actions = new ArrayList<>(); - - if (null != notify) { - setNotify(notify); - } - - if (null != highlight) { - setHighlight(highlight); - } - - if (sound) { - setNotificationSound(); - } - } - - /** - * Build a bing rule from another one. - * - * @param otherRule the other rule - */ - public BingRule(BingRule otherRule) { - ruleId = otherRule.ruleId; - - if (null != otherRule.conditions) { - conditions = new ArrayList<>(otherRule.conditions); - } - - if (null != otherRule.actions) { - actions = new ArrayList<>(otherRule.actions); - } - - isDefault = otherRule.isDefault; - isEnabled = otherRule.isEnabled; - kind = otherRule.kind; - } - - /** - * Add a condition to the rule. - * - * @param condition the condition to add. - */ - public void addCondition(Condition condition) { - if (null == conditions) { - conditions = new ArrayList<>(); - } - conditions.add(condition); - } - - /** - * Search an action map from its tweak. - * - * @param tweak the tweak name. - * @return the action map. null if not found. - */ - public Map getActionMap(String tweak) { - if ((null != actions) && !TextUtils.isEmpty(tweak)) { - for (Object action : actions) { - if (action instanceof Map) { - try { - Map actionMap = ((Map) action); - - if (TextUtils.equals((String) actionMap.get(ACTION_PARAMETER_SET_TWEAK), tweak)) { - return actionMap; - } - } catch (Exception e) { - Log.e(LOG_TAG, "## getActionMap() : " + e.getMessage(), e); - } - } - } - } - - return null; - } - - /** - * Check if the sound type is the default notification sound. - * - * @param sound the sound name. - * @return true if the sound is the default notification sound. - */ - public static boolean isDefaultNotificationSound(String sound) { - return ACTION_VALUE_DEFAULT.equals(sound); - } - - /** - * Check if the sound type is the call ring. - * - * @param sound the sound name. - * @return true if the sound is the call ring. - */ - public static boolean isCallRingNotificationSound(String sound) { - return ACTION_VALUE_RING.equals(sound); - } - - /** - * @return the notification sound (null if it is not defined) - */ - public String getNotificationSound() { - String sound = null; - Map actionMap = getActionMap(ACTION_SET_TWEAK_SOUND_VALUE); - - if ((null != actionMap) && actionMap.containsKey(ACTION_PARAMETER_VALUE)) { - sound = (String) actionMap.get(ACTION_PARAMETER_VALUE); - } - - return sound; - } - - /** - * Add the default notification sound. - */ - public void setNotificationSound() { - setNotificationSound(ACTION_VALUE_DEFAULT); - } - - /** - * Set the notification sound - * - * @param sound notification sound - */ - public void setNotificationSound(String sound) { - removeNotificationSound(); - - if (!TextUtils.isEmpty(sound)) { - Map actionMap = new HashMap<>(); - actionMap.put(ACTION_PARAMETER_SET_TWEAK, ACTION_SET_TWEAK_SOUND_VALUE); - actionMap.put(ACTION_PARAMETER_VALUE, sound); - actions.add(actionMap); - } - } - - /** - * Remove the notification sound - */ - public void removeNotificationSound() { - Map actionMap = getActionMap(ACTION_SET_TWEAK_SOUND_VALUE); - - if (null != actionMap) { - actions.remove(actionMap); - } - } - - /** - * Set the highlight status. - * - * @param highlight the highlight status - */ - public void setHighlight(boolean highlight) { - Map actionMap = getActionMap(ACTION_SET_TWEAK_HIGHLIGHT_VALUE); - - if (null == actionMap) { - actionMap = new HashMap<>(); - actionMap.put(ACTION_PARAMETER_SET_TWEAK, ACTION_SET_TWEAK_HIGHLIGHT_VALUE); - actions.add(actionMap); - } - - if (highlight) { - actionMap.remove(ACTION_PARAMETER_VALUE); - } else { - actionMap.put(ACTION_PARAMETER_VALUE, false); - } - } - - /** - * Return true if the rule should highlight the event. - * - * @return true if the rule should play sound - */ - public boolean shouldHighlight() { - boolean shouldHighlight = false; - - Map actionMap = getActionMap(ACTION_SET_TWEAK_HIGHLIGHT_VALUE); - - if (null != actionMap) { - // default behaviour - shouldHighlight = true; - - if (actionMap.containsKey(ACTION_PARAMETER_VALUE)) { - Object valueAsVoid = actionMap.get(ACTION_PARAMETER_VALUE); - - if (valueAsVoid instanceof Boolean) { - shouldHighlight = (boolean) valueAsVoid; - } else if (valueAsVoid instanceof String) { - shouldHighlight = TextUtils.equals((String)valueAsVoid, "true"); - } else { - Log.e(LOG_TAG, "## shouldHighlight() : unexpected type " + valueAsVoid); - } - } - } - - return shouldHighlight; - } - - /** - * Set the notification status. - * - * @param notify true to notify - */ - public void setNotify(boolean notify) { - if (notify) { - actions.remove(ACTION_DONT_NOTIFY); - - if (!actions.contains(ACTION_NOTIFY)) { - actions.add(ACTION_NOTIFY); - } - } else { - actions.remove(ACTION_NOTIFY); - - if (!actions.contains(ACTION_DONT_NOTIFY)) { - actions.add(ACTION_DONT_NOTIFY); - } - } - } - - /** - * Return true if the rule should highlight the event. - * - * @return true if the rule should play sound - */ - public boolean shouldNotify() { - return actions.contains(ACTION_NOTIFY); - } - - /** - * Return true if the rule should not highlight the event. - * - * @return true if the rule should not play sound - */ - public boolean shouldNotNotify() { - return actions.contains(ACTION_DONT_NOTIFY); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/Condition.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/Condition.java deleted file mode 100644 index 51f1c270..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/Condition.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.bingrules; - - -public class Condition { - // defined in the push rules spec - // https://matrix.org/docs/spec/client_server/r0.3.0.html#push-rules - - /* 'key': The dot-separated field of the event to match, eg. content.body - 'pattern': The glob-style pattern to match against. Patterns with no special glob characters should be treated as having asterisks prepended - and appended when testing the condition.*/ - public static final String KIND_EVENT_MATCH = "event_match"; - - /* 'profile_tag': The profile_tag to match with.*/ - public static final String KIND_PROFILE_TAG = "profile_tag"; - - /* no parameter */ - public static final String KIND_CONTAINS_DISPLAY_NAME = "contains_display_name"; - - /* 'is': A decimal integer optionally prefixed by one of, '==', '<', '>', '>=' or '<='. - A prefix of '<' matches rooms where the member count is strictly less than the given number and so forth. If no prefix is present, this matches - rooms where the member count is exactly equal to the given number (ie. the same as '=='). - */ - public static final String KIND_ROOM_MEMBER_COUNT = "room_member_count"; - - /* */ - public static final String KIND_DEVICE = "device"; - - public static final String KIND_SENDER_NOTIFICATION_PERMISSION = "sender_notification_permission"; - - public static final String KIND_UNKNOWN = "unknown_condition"; - - public String kind; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/ContainsDisplayNameCondition.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/ContainsDisplayNameCondition.java deleted file mode 100644 index f641a3db..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/ContainsDisplayNameCondition.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.bingrules; - -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.message.Message; -import im.vector.matrix.android.internal.legacy.util.EventUtils; -import im.vector.matrix.android.internal.legacy.util.JsonUtils; - -/** - * Bing rule condition that is satisfied when a message body contains the user's current display name. - */ -public class ContainsDisplayNameCondition extends Condition { - public ContainsDisplayNameCondition() { - kind = Condition.KIND_CONTAINS_DISPLAY_NAME; - } - - public boolean isSatisfied(Event event, String myDisplayName) { - if (Event.EVENT_TYPE_MESSAGE.equals(event.getType())) { - Message msg = JsonUtils.toMessage(event.getContent()); - - if (null != msg) { - return EventUtils.caseInsensitiveFind(myDisplayName, msg.body); - } - } - return false; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/ContentRule.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/ContentRule.java deleted file mode 100644 index e34ded8d..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/ContentRule.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.bingrules; - -public class ContentRule extends BingRule { - public String pattern; - - public ContentRule(String ruleKind, String aPattern, boolean notify, boolean highlight, boolean sound) { - super(ruleKind, aPattern, notify, highlight, sound); - pattern = aPattern; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/DeviceCondition.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/DeviceCondition.java deleted file mode 100644 index 6585e3bc..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/DeviceCondition.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.bingrules; - -public class DeviceCondition extends Condition { - public String profileTag; - - public DeviceCondition() { - kind = Condition.KIND_DEVICE; - } - - @Override - public String toString() { - return "DeviceCondition{" + "profileTag='" + profileTag + "'}'"; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/EventMatchCondition.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/EventMatchCondition.java deleted file mode 100644 index aad33413..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/EventMatchCondition.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.bingrules; - -import android.text.TextUtils; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; - -import im.vector.matrix.android.internal.legacy.rest.model.Event; - -import java.util.HashMap; -import java.util.Map; -import java.util.regex.Pattern; - -public class EventMatchCondition extends Condition { - - public String key; - public String pattern; - - private static Map mPatternByRule = null; - - public EventMatchCondition() { - kind = Condition.KIND_EVENT_MATCH; - } - - @Override - public String toString() { - return "EventMatchCondition{" + "key='" + key + ", pattern=" + pattern + '}'; - } - - /** - * Returns whether the given event satisfies the condition. - * - * @param event the event - * @return true if the event satisfies the condition - */ - public boolean isSatisfied(Event event) { - String fieldVal = null; - - // some information are in the decrypted event (like type) - if (event.isEncrypted() && (null != event.getClearEvent())) { - JsonObject eventJson = event.getClearEvent().toJsonObject(); - fieldVal = extractField(eventJson, key); - } - - if (TextUtils.isEmpty(fieldVal)) { - JsonObject eventJson = event.toJsonObject(); - fieldVal = extractField(eventJson, key); - } - - if (TextUtils.isEmpty(fieldVal)) { - return false; - } - - if (TextUtils.equals(pattern, fieldVal)) { - return true; - } - - if (null == mPatternByRule) { - mPatternByRule = new HashMap<>(); - } - - Pattern patternEx = mPatternByRule.get(pattern); - - if (null == patternEx) { - patternEx = Pattern.compile(globToRegex(pattern), Pattern.CASE_INSENSITIVE); - mPatternByRule.put(pattern, patternEx); - } - - return patternEx.matcher(fieldVal).matches(); - } - - private String extractField(JsonObject jsonObject, String fieldPath) { - String[] fieldParts = fieldPath.split("\\."); - JsonElement jsonElement = null; - for (String field : fieldParts) { - jsonElement = jsonObject.get(field); - if (jsonElement == null) { - return null; - } - if (jsonElement.isJsonObject()) { - jsonObject = (JsonObject) jsonElement; - } - } - return (jsonElement == null) ? null : jsonElement.getAsString(); - } - - private String globToRegex(String glob) { - String res = glob.replace("*", ".*").replace("?", "."); - - // If no special characters were found (detected here by no replacements having been made), - // add asterisks and boundaries to both sides - if (res.equals(glob)) { - res = "(^|.*\\W)" + res + "($|\\W.*)"; - } - return res; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/PushRuleSet.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/PushRuleSet.java deleted file mode 100644 index 7cdf3459..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/PushRuleSet.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.bingrules; - -import android.text.TextUtils; - -import java.util.ArrayList; -import java.util.List; - -public class PushRuleSet { - public List override; - public List content; - public List room; - public List sender; - public List underride; - - /** - * Constructor - */ - public PushRuleSet() { - override = new ArrayList<>(); - content = new ArrayList<>(); - room = new ArrayList<>(); - sender = new ArrayList<>(); - underride = new ArrayList<>(); - } - - /** - * Find a rule from its rule ID. - * - * @param rules the rules list. - * @param ruleID the rule ID. - * @return the bing rule if it exists, else null. - */ - private BingRule findRule(List rules, String ruleID) { - for (BingRule rule : rules) { - if (TextUtils.equals(ruleID, rule.ruleId)) { - return rule; - } - } - return null; - } - - private List getBingRulesList(String kind) { - List res = null; - - if (BingRule.KIND_OVERRIDE.equals(kind)) { - res = override; - } else if (BingRule.KIND_ROOM.equals(kind)) { - res = room; - } else if (BingRule.KIND_SENDER.equals(kind)) { - res = sender; - } else if (BingRule.KIND_UNDERRIDE.equals(kind)) { - res = underride; - } - - return res; - } - - /** - * Add a rule from the bingRules - * - * @param rule the rule to add. - */ - public void addAtTop(BingRule rule) { - if (TextUtils.equals(BingRule.KIND_CONTENT, rule.kind)) { - if (null != content) { - if (rule instanceof ContentRule) { - content.add(0, (ContentRule) rule); - } - } - } else { - List rulesList = getBingRulesList(rule.kind); - - if (null != rulesList) { - rulesList.add(0, rule); - } - } - } - - /** - * Remove a rule from the bingRules - * - * @param rule the rule to delete. - * @return true if the rule has been deleted - */ - public boolean remove(BingRule rule) { - boolean res = false; - - if (BingRule.KIND_CONTENT.equals(rule.kind)) { - if (null != content) { - res = content.remove(rule); - } - } else { - List rulesList = getBingRulesList(rule.kind); - - if (null != rulesList) { - res = rulesList.remove(rule); - } - } - - return res; - } - - /** - * Find a rule from its rule ID. - * - * @param rules the rules list. - * @param ruleID the rule ID. - * @return the bing rule if it exists, else null. - */ - private BingRule findContentRule(List rules, String ruleID) { - for (BingRule rule : rules) { - if (TextUtils.equals(ruleID, rule.ruleId)) { - return rule; - } - } - return null; - } - - /** - * Find a rule from its ruleID. - * - * @param ruleId a RULE_ID_XX value - * @return the matched bing rule or null it doesn't exist. - */ - public BingRule findDefaultRule(String ruleId) { - BingRule rule = null; - - // sanity check - if (null != ruleId) { - if (TextUtils.equals(BingRule.RULE_ID_CONTAIN_USER_NAME, ruleId)) { - rule = findContentRule(content, ruleId); - } else { - // assume that the ruleId is unique. - rule = findRule(override, ruleId); - - if (null == rule) { - rule = findRule(underride, ruleId); - } - } - } - - return rule; - } - - /** - * Return the content rules list. - * - * @return the content rules list. - */ - public List getContentRules() { - List res = new ArrayList<>(); - - if (null != content) { - for (BingRule rule : content) { - if (!rule.ruleId.startsWith(".m.")) { - res.add(rule); - } - } - } - - return res; - } - - /** - * Return the room rules list. - * - * @return the room rules list. - */ - public List getRoomRules() { - if (null == room) { - return new ArrayList<>(); - } else { - return room; - } - } - - /** - * Return the room rules list. - * - * @return the sender rules list. - */ - public List getSenderRules() { - if (null == sender) { - return new ArrayList<>(); - } else { - return sender; - } - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/PushRulesResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/PushRulesResponse.java deleted file mode 100644 index 9e94c00a..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/PushRulesResponse.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.bingrules; - -public class PushRulesResponse { - public PushRuleSet device; - public PushRuleSet global; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/RoomMemberCountCondition.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/RoomMemberCountCondition.java deleted file mode 100644 index 56b542df..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/RoomMemberCountCondition.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.bingrules; - -import im.vector.matrix.android.internal.legacy.util.Log; -import im.vector.matrix.android.internal.legacy.data.Room; - -public class RoomMemberCountCondition extends Condition { - - private static final String LOG_TAG = RoomMemberCountCondition.class.getSimpleName(); - - // NB: Leave the strings in order of descending length - private static final String[] PREFIX_ARR = new String[]{"==", "<=", ">=", "<", ">", ""}; - - public String is; - private String comparisonPrefix = null; - private int limit; - private boolean parseError = false; - - public RoomMemberCountCondition() { - kind = Condition.KIND_ROOM_MEMBER_COUNT; - } - - @Override - public String toString() { - return "RoomMemberCountCondition{" + "is='" + is + "'}'"; - } - - @SuppressWarnings("SimplifiableIfStatement") - public boolean isSatisfied(Room room) { - // sanity check - if (room == null) return false; - - if (parseError) return false; - - // Parse the is field into prefix and number the first time - if (comparisonPrefix == null) { - parseIsField(); - if (parseError) return false; - } - - int numMembers = room.getNumberOfJoinedMembers(); - - if ("==".equals(comparisonPrefix) || "".equals(comparisonPrefix)) { - return numMembers == limit; - } - if ("<".equals(comparisonPrefix)) { - return numMembers < limit; - } - if (">".equals(comparisonPrefix)) { - return numMembers > limit; - } - if ("<=".equals(comparisonPrefix)) { - return numMembers <= limit; - } - if (">=".equals(comparisonPrefix)) { - return numMembers >= limit; - } - - return false; - } - - /** - * Parse the is field to extract meaningful information. - */ - protected void parseIsField() { - for (String prefix : PREFIX_ARR) { - if (is.startsWith(prefix)) { - comparisonPrefix = prefix; - break; - } - } - - if (comparisonPrefix == null) { - parseError = true; - } else { - try { - limit = Integer.parseInt(is.substring(comparisonPrefix.length())); - } catch (NumberFormatException e) { - parseError = true; - } - } - - if (parseError) { - Log.e(LOG_TAG, "parsing error : " + is); - } - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/SenderNotificationPermissionCondition.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/SenderNotificationPermissionCondition.java deleted file mode 100644 index d8ada7b9..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/SenderNotificationPermissionCondition.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.bingrules; - -import im.vector.matrix.android.internal.legacy.rest.model.PowerLevels; - -public class SenderNotificationPermissionCondition extends Condition { - private static final String LOG_TAG = SenderNotificationPermissionCondition.class.getSimpleName(); - - public String key; - - public SenderNotificationPermissionCondition() { - kind = Condition.KIND_SENDER_NOTIFICATION_PERMISSION; - } - - public boolean isSatisfied(PowerLevels powerLevels, String userId) { - return (null != powerLevels) && (null != userId) && powerLevels.getUserPowerLevel(userId) >= powerLevels.notificationLevel(key); - } - - @Override - public String toString() { - return "SenderNotificationPermissionCondition{" + "key=" + key; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/UnknownCondition.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/UnknownCondition.java deleted file mode 100644 index c94fcf4e..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/bingrules/UnknownCondition.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.bingrules; - -import im.vector.matrix.android.internal.legacy.rest.model.Event; - -public class UnknownCondition extends Condition { - public UnknownCondition() { - kind = Condition.KIND_UNKNOWN; - } - - // unknown conditions: we previously matched all unknown conditions, - // but given that rules can be added to the base rules on a server, - // it's probably better to not match unknown conditions. - public boolean isSatisfied(Event event) { - return false; - } - - @Override - public String toString() { - return "UnknownCondition"; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/EncryptedBodyFileInfo.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/EncryptedBodyFileInfo.java deleted file mode 100644 index 40f5221a..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/EncryptedBodyFileInfo.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.crypto; - -import org.matrix.olm.OlmPkMessage; - -public class EncryptedBodyFileInfo { - public String ciphertext; - public String mac; - public String ephemeral; - - /** - * Build from a OlmPkMessage object - * - * @param olmPkMessage OlmPkMessage - */ - public EncryptedBodyFileInfo(OlmPkMessage olmPkMessage) { - ciphertext = olmPkMessage.mCipherText; - mac = olmPkMessage.mMac; - ephemeral = olmPkMessage.mEphemeralKey; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/EncryptedEventContent.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/EncryptedEventContent.java deleted file mode 100644 index fe340654..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/EncryptedEventContent.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.rest.model.crypto; - -/** - * Class representing an encrypted event content - */ -public class EncryptedEventContent implements java.io.Serializable { - - /** - * the used algorithm - */ - public String algorithm; - - /** - * The encrypted event - */ - public String ciphertext; - - /** - * The device id - */ - public String device_id; - - /** - * the sender key - */ - public String sender_key; - - /** - * The session id - */ - public String session_id; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/EncryptedFileInfo.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/EncryptedFileInfo.java deleted file mode 100644 index cb4229ae..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/EncryptedFileInfo.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.rest.model.crypto; - -import java.io.Serializable; -import java.util.Map; - -public class EncryptedFileInfo implements Serializable{ - public String url; - public String mimetype; - public EncryptedFileKey key; - public String iv; - public Map hashes; - public String v; - - /** - * Make a deep copy. - * @return the copy - */ - public EncryptedFileInfo deepCopy() { - EncryptedFileInfo encryptedFile = new EncryptedFileInfo(); - encryptedFile.url = url; - encryptedFile.mimetype = mimetype; - - if (null != key) { - encryptedFile.key = key.deepCopy(); - } - - encryptedFile.iv = iv; - encryptedFile.hashes = hashes; - - return encryptedFile; - } -} - - - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/EncryptedFileKey.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/EncryptedFileKey.java deleted file mode 100644 index b5ae311c..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/EncryptedFileKey.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.rest.model.crypto; - -import java.io.Serializable; -import java.util.List; - -public class EncryptedFileKey implements Serializable { - public String alg; - public Boolean ext; - public List key_ops; - public String kty; - public String k; - - /** - * Make a deep copy. - * - * @return the copy - */ - public EncryptedFileKey deepCopy() { - EncryptedFileKey encryptedFileKey = new EncryptedFileKey(); - - encryptedFileKey.alg = alg; - encryptedFileKey.ext = ext; - encryptedFileKey.key_ops = key_ops; - encryptedFileKey.kty = kty; - encryptedFileKey.k = k; - - return encryptedFileKey; - } -} - - - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/ForwardedRoomKeyContent.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/ForwardedRoomKeyContent.java deleted file mode 100644 index a3385aae..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/ForwardedRoomKeyContent.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.rest.model.crypto; - -import java.util.List; - -/** - * Class representing the forward room key request body content - */ -public class ForwardedRoomKeyContent implements java.io.Serializable { - public String algorithm; - - public String room_id; - - public String sender_key; - - public String session_id; - - public String session_key; - - public List forwarding_curve25519_key_chain; - - public String sender_claimed_ed25519_key; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/KeyChangesResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/KeyChangesResponse.java deleted file mode 100644 index 1865b276..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/KeyChangesResponse.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.rest.model.crypto; - -import java.util.List; - -/** - * This class describes the key changes response - */ -public class KeyChangesResponse { - // list of user ids which have new devices - public List changed; - - // List of user ids who are no more tracked. - public List left; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/KeysClaimResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/KeysClaimResponse.java deleted file mode 100644 index fa374438..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/KeysClaimResponse.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.rest.model.crypto; - -import java.util.Map; - -/** - * This class represents the response to /keys/query request made by claimOneTimeKeysForUsersDevices. - */ -public class KeysClaimResponse { - /** - * The requested keys ordered by device by user. - */ - public Map>>> oneTimeKeys; -} - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/KeysQueryResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/KeysQueryResponse.java deleted file mode 100644 index 62e1acba..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/KeysQueryResponse.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.rest.model.crypto; - -import im.vector.matrix.android.internal.legacy.crypto.data.MXDeviceInfo; - -import java.util.Map; - -/** - * This class represents the response to /keys/query request made by downloadKeysForUsers - */ -public class KeysQueryResponse { - /** - * The device keys per devices per users. - */ - public Map> deviceKeys; - - /** - * The failures sorted by homeservers. - */ - public Map> failures; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/KeysUploadResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/KeysUploadResponse.java deleted file mode 100644 index 5b35cb7c..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/KeysUploadResponse.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.rest.model.crypto; - -import android.text.TextUtils; - -import java.util.Map; - -/** - * This class represents the response to /keys/upload request made by uploadKeys. - */ -public class KeysUploadResponse { - - /** - * The count per algorithm as returned by the home server: a map (algorithm to count). - */ - public Map oneTimeKeyCounts; - - /** - * Helper methods to extract information from 'oneTimeKeyCounts' - * - * @param algorithm the expected algorithm - * @return the time key counts - */ - public int oneTimeKeyCountsForAlgorithm(String algorithm) { - int res = 0; - - if ((null != oneTimeKeyCounts) && !TextUtils.isEmpty(algorithm)) { - Integer val = oneTimeKeyCounts.get(algorithm); - - if (null != val) { - res = val.intValue(); - } - } - - return res; - } - - /** - * Tells if there is a oneTimeKeys for a dedicated algorithm. - * - * @param algorithm the algorithm - * @return true if it is found - */ - public boolean hasOneTimeKeyCountsForAlgorithm(String algorithm) { - return (null != oneTimeKeyCounts) && (null != algorithm) && oneTimeKeyCounts.containsKey(algorithm); - } -} - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/NewDeviceContent.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/NewDeviceContent.java deleted file mode 100644 index 05eb31c2..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/NewDeviceContent.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.rest.model.crypto; - -import java.util.List; - -public class NewDeviceContent { - private static final String LOG_TAG = "NewDeviceContent"; - - // the device id - public String deviceId; - - // the room ids list - public List rooms; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/OlmEventContent.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/OlmEventContent.java deleted file mode 100644 index 67def0ce..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/OlmEventContent.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.rest.model.crypto; - -import java.util.Map; - -/** - * Class representing an encrypted event content - */ -public class OlmEventContent implements java.io.Serializable { - /** - * - */ - public Map ciphertext; - - /** - * The device id - */ - //public String device_id; - - /** - * the sender key - */ - public String sender_key; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/OlmPayloadContent.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/OlmPayloadContent.java deleted file mode 100644 index 6ff0eea7..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/OlmPayloadContent.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.rest.model.crypto; - -import java.util.Map; - -/** - * Class representing the OLM payload content - */ -public class OlmPayloadContent implements java.io.Serializable { - /** - * The room id - */ - public String room_id; - - /** - * The sender - */ - public String sender; - - /** - * The receipient - */ - public String recipient; - - /** - * the recipient keys - */ - public Map recipient_keys; - - /** - * The keys - */ - public Map keys; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/RoomKeyContent.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/RoomKeyContent.java deleted file mode 100644 index 034a6492..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/RoomKeyContent.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.rest.model.crypto; - -/** - * Class representing an sharekey content - */ -public class RoomKeyContent implements java.io.Serializable { - - public String algorithm; - - public String room_id; - - public String session_id; - - public String session_key; - - // should be a Long but it is sometimes a double - public Object chain_index; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/RoomKeyRequest.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/RoomKeyRequest.java deleted file mode 100644 index d3c60d9d..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/RoomKeyRequest.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.rest.model.crypto; - -/** - * Class representing an room key request content - */ -public class RoomKeyRequest implements java.io.Serializable { - public static final String ACTION_REQUEST = "request"; - public static final String ACTION_REQUEST_CANCELLATION = "request_cancellation"; - - public String action; - - public String requesting_device_id; - - public String request_id; - - public RoomKeyRequestBody body; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/RoomKeyRequestBody.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/RoomKeyRequestBody.java deleted file mode 100644 index 7e6b9156..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/crypto/RoomKeyRequestBody.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.rest.model.crypto; - -/** - * Class representing an room key request body content - */ -public class RoomKeyRequestBody implements java.io.Serializable { - public String algorithm; - - public String room_id; - - public String sender_key; - - public String session_id; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/filter/RoomEventFilter.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/filter/RoomEventFilter.java deleted file mode 100644 index 54c8c481..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/filter/RoomEventFilter.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2018 Matthias Kesler - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.filter; - -import com.google.gson.annotations.SerializedName; - -import im.vector.matrix.android.internal.legacy.util.JsonUtils; - -import java.util.List; - -/** - * Represents "RoomEventFilter" as mentioned in the SPEC - * https://matrix.org/docs/spec/client_server/r0.3.0.html#post-matrix-client-r0-user-userid-filter - */ -public class RoomEventFilter { - - public Integer limit; - - @SerializedName("not_senders") - public List notSenders; - - @SerializedName("not_types") - public List notTypes; - - public List senders; - - public List types; - - public List rooms; - - @SerializedName("not_rooms") - public List notRooms; - - @SerializedName("contains_url") - public Boolean containsUrl; - - @SerializedName("lazy_load_members") - public Boolean lazyLoadMembers; - - public boolean hasData() { - return limit != null - || notSenders != null - || notTypes != null - || senders != null - || types != null - || rooms != null - || notRooms != null - || containsUrl != null - || lazyLoadMembers != null; - } - - public String toJSONString() { - return JsonUtils.getGson(false).toJson(this); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/AcceptGroupInvitationParams.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/AcceptGroupInvitationParams.java deleted file mode 100644 index 53f3a289..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/AcceptGroupInvitationParams.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.group; - -/** - * Accept an invitation in a group - */ -public class AcceptGroupInvitationParams { -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/AddGroupParams.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/AddGroupParams.java deleted file mode 100644 index 251cb296..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/AddGroupParams.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.group; - -/** - * Room addition to a group - */ -public class AddGroupParams { -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/CreateGroupParams.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/CreateGroupParams.java deleted file mode 100644 index 80cabed8..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/CreateGroupParams.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.group; - - -/** - * Group creation params - */ -public class CreateGroupParams { - /** - * The group local part - */ - public String localpart; - - /** - * The group profile - */ - public GroupProfile profile; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/CreateGroupResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/CreateGroupResponse.java deleted file mode 100644 index 47caaab4..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/CreateGroupResponse.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.group; - -/** - * Group creation response - */ -public class CreateGroupResponse { - /** - * The group Id - */ - public String group_id; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GetGroupsResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GetGroupsResponse.java deleted file mode 100644 index d3058646..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GetGroupsResponse.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.group; - -import java.util.List; - -/** - * Get groups list response - */ -public class GetGroupsResponse { - /** - * Group ids list - */ - public List groupIds; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GetPublicisedGroupsResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GetPublicisedGroupsResponse.java deleted file mode 100644 index 258fbf60..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GetPublicisedGroupsResponse.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.group; - -import java.util.List; -import java.util.Map; - -/** - * Get groups list response - */ -public class GetPublicisedGroupsResponse { - /** - * Group ids list indexed by userId - */ - public Map> users; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GetUserPublicisedGroupsResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GetUserPublicisedGroupsResponse.java deleted file mode 100644 index 77c54202..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GetUserPublicisedGroupsResponse.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.group; - -import java.util.List; - -/** - * Get groups list response - */ -public class GetUserPublicisedGroupsResponse { - /** - * Group ids list - */ - public List groups; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/Group.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/Group.java deleted file mode 100644 index 9ccb54f2..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/Group.java +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.group; - -import android.text.TextUtils; - -import im.vector.matrix.android.internal.legacy.rest.model.RoomMember; - -import java.io.Serializable; -import java.util.Comparator; - -/** - * This class represents a community in Matrix. - */ -public class Group implements Serializable { - /** - * Sort by group id - */ - public static final Comparator mGroupsComparator = new Comparator() { - public int compare(Group group1, Group group2) { - return group1.getGroupId().compareTo(group2.getGroupId()); - } - }; - - /** - * The group id. - */ - private String mGroupId; - - /** - * The community summary. - */ - private GroupSummary mSummary = new GroupSummary(); - - /** - * The rooms of the community. - */ - private GroupRooms mRooms = new GroupRooms(); - - /** - * The community members. - */ - private GroupUsers mUsers = new GroupUsers(); - - /** - * The community invited members. - */ - private GroupUsers mInvitedUsers = new GroupUsers(); - - /** - * The user membership. - */ - private String mMembership; - - /** - * The identifier of the potential inviter (tells wether an invite is pending for this group). - */ - private String mInviter; - - /** - * Create an instance with a group id. - * - * @param groupId the identifier. - * @return the MXGroup instance. - */ - public Group(String groupId) { - mGroupId = groupId; - } - - /** - * @return the group ID - */ - public String getGroupId() { - return mGroupId; - } - - /** - * Update the group profile. - * - * @param profile the group profile. - */ - public void setGroupProfile(GroupProfile profile) { - if (null == mSummary) { - mSummary = new GroupSummary(); - } - - getGroupSummary().profile = profile; - } - - /** - * @return the group profile - */ - public GroupProfile getGroupProfile() { - if (null != getGroupSummary()) { - return getGroupSummary().profile; - } - - return null; - } - - /** - * @return the group name - */ - public String getDisplayName() { - String name = null; - - if (null != getGroupProfile()) { - name = getGroupProfile().name; - } - - if (TextUtils.isEmpty(name)) { - name = getGroupId(); - } - - return name; - } - - /** - * @return the group long description - */ - public String getLongDescription() { - if (null != getGroupProfile()) { - return getGroupProfile().longDescription; - } - - return null; - } - - /** - * @return the avatar URL - */ - public String getAvatarUrl() { - if (null != getGroupProfile()) { - return getGroupProfile().avatarUrl; - } - - return null; - } - - /** - * @return the short description - */ - public String getShortDescription() { - if (null != getGroupProfile()) { - return getGroupProfile().shortDescription; - } - - return null; - } - - /** - * Tells if the group is public. - * - * @return true if the group is public. - */ - public boolean isPublic() { - return (null != getGroupProfile()) && (null != getGroupProfile().isPublic) && getGroupProfile().isPublic; - } - - /** - * Tells if the user is invited to this group. - * - * @return true if the user is invited - */ - public boolean isInvited() { - return TextUtils.equals(mMembership, RoomMember.MEMBERSHIP_INVITE); - } - - /** - * @return the group summary - */ - public GroupSummary getGroupSummary() { - return mSummary; - } - - /** - * Update the group summary - * - * @param aGroupSummary the new group summary - */ - public void setGroupSummary(GroupSummary aGroupSummary) { - mSummary = aGroupSummary; - } - - /** - * @return the group rooms - */ - public GroupRooms getGroupRooms() { - return mRooms; - } - - /** - * Update the group rooms - * - * @param aGroupRooms the new group rooms - */ - public void setGroupRooms(GroupRooms aGroupRooms) { - mRooms = aGroupRooms; - } - - /** - * @return the group users - */ - public GroupUsers getGroupUsers() { - return mUsers; - } - - /** - * Update the group users - * - * @param aGroupUsers the group users - */ - public void setGroupUsers(GroupUsers aGroupUsers) { - mUsers = aGroupUsers; - } - - /** - * @return the invited group users - */ - public GroupUsers getInvitedGroupUsers() { - return mInvitedUsers; - } - - /** - * Update the invited group users - * - * @param aGroupUsers the group users - */ - public void setInvitedGroupUsers(GroupUsers aGroupUsers) { - mInvitedUsers = aGroupUsers; - } - - /** - * Update the membership - * - * @param membership the new membership - */ - public void setMembership(String membership) { - mMembership = membership; - } - - /** - * @return the membership - */ - public String getMembership() { - return mMembership; - } - - /** - * @return the inviter - */ - public String getInviter() { - return mInviter; - } - - /** - * Update the inviter. - * - * @param inviter the inviter. - */ - public void setInviter(String inviter) { - mInviter = inviter; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupInviteUserParams.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupInviteUserParams.java deleted file mode 100644 index b534ff5a..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupInviteUserParams.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.group; - -/** - * Group user invitation parameters - */ -public class GroupInviteUserParams { -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupInviteUserResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupInviteUserResponse.java deleted file mode 100644 index 03326d7f..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupInviteUserResponse.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.group; - -/** - * Group user invitation response - */ -public class GroupInviteUserResponse { - /** - * The user state - *

- * join - the invitee’s HS immediately accepted the invite - * invite - the invitee’s HS accepted the invite, and then may relay to invitee’s clients - * reject - the invitee’s HS immediately rejected the invite - */ - public String state; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupKickUserParams.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupKickUserParams.java deleted file mode 100644 index 0e657a07..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupKickUserParams.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.group; - -/** - * Group user kick parameters - */ -public class GroupKickUserParams { -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupProfile.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupProfile.java deleted file mode 100644 index bc73e71b..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupProfile.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.group; - -import java.io.Serializable; - -/** - * This class represents a community profile in the server responses. - */ -public class GroupProfile implements Serializable { - - public String shortDescription; - - /** - * Tell whether the group is public. - */ - public Boolean isPublic; - - /** - * The URL for the group's avatar. May be nil. - */ - public String avatarUrl; - - /** - * The group's name. - */ - public String name; - - /** - * The optional HTML formatted string used to described the group. - */ - public String longDescription; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupRoom.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupRoom.java deleted file mode 100644 index 7b06a60a..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupRoom.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.group; - -import android.text.TextUtils; - -import im.vector.matrix.android.internal.legacy.rest.model.publicroom.PublicRoom; - -/** - * This class represents a room linked to a community - */ -public class GroupRoom extends PublicRoom { - - /** - * @return the display name - */ - public String getDisplayName() { - if (!TextUtils.isEmpty(name)) { - return name; - } - - if (!TextUtils.isEmpty(canonicalAlias)) { - return canonicalAlias; - } - - return roomId; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupRooms.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupRooms.java deleted file mode 100644 index a04e121c..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupRooms.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.group; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -/** - * This class represents the group rooms in the server response. - */ -public class GroupRooms implements Serializable { - // estimated room count - public Integer totalRoomCountEstimate; - - // rooms list - public List chunk; - - /** - * @return the rooms list - */ - public List getRoomsList() { - if (null == chunk) { - chunk = new ArrayList<>(); - } - - return chunk; - } - - /** - * @return the estimated rooms count - */ - public int getEstimatedRoomCount() { - if (null == totalRoomCountEstimate) { - totalRoomCountEstimate = getRoomsList().size(); - } - - return totalRoomCountEstimate; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupSummary.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupSummary.java deleted file mode 100644 index 87b768f5..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupSummary.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.group; - -import java.io.Serializable; - -/** - * This class represents the summary of a community in the server response. - */ -public class GroupSummary implements Serializable { - /** - * The group profile. - */ - public GroupProfile profile; - - /** - * The group users. - */ - public GroupSummaryUsersSection usersSection; - - /** - * The current user status. - */ - public GroupSummaryUser user; - - /** - * The rooms linked to the community. - */ - public GroupSummaryRoomsSection roomsSection; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupSummaryRoomsSection.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupSummaryRoomsSection.java deleted file mode 100644 index 15f88cbb..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupSummaryRoomsSection.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.group; - -import java.io.Serializable; -import java.util.List; - -/** - * This class represents the community rooms in a group summary response. - */ -public class GroupSummaryRoomsSection implements Serializable { - - public Integer totalRoomCountEstimate; - - public List rooms; - - // @TODO: Check the meaning and the usage of these categories. This dictionary is empty FTM. - //public Map categories; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupSummaryUser.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupSummaryUser.java deleted file mode 100644 index 09168bee..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupSummaryUser.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.group; - -import java.io.Serializable; - -/** - * This class represents the current user status in a group summary response. - */ -public class GroupSummaryUser implements Serializable { - - /** - * The current user membership in this community. - */ - public String membership; - - /** - * Tell whether the user published this community on his profile. - */ - public Boolean isPublicised; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupSummaryUsersSection.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupSummaryUsersSection.java deleted file mode 100644 index 9b56cade..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupSummaryUsersSection.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.group; - -import java.io.Serializable; -import java.util.List; - -/** - * This class represents the community members in a group summary response. - */ -public class GroupSummaryUsersSection implements Serializable { - - public Integer totalUserCountEstimate; - - public List users; - - // @TODO: Check the meaning and the usage of these roles. This dictionary is empty FTM. - //public Map roles; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupSyncProfile.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupSyncProfile.java deleted file mode 100644 index dbc323f2..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupSyncProfile.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.group; - -import java.io.Serializable; - -/** - * Group sync profile - */ -public class GroupSyncProfile { - /** - * The name of the group, if any. May be nil. - */ - public String name; - - /** - * The URL for the group's avatar. May be nil. - */ - public String avatarUrl; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupUser.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupUser.java deleted file mode 100644 index 9e0aee70..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupUser.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.group; - -import java.io.Serializable; - -/** - * This class represents a community member - */ -public class GroupUser implements Serializable { - /** - * The user display name. - */ - public String displayname; - - /** - * The ID of the user. - */ - public String userId; - - /** - * Tell whether the user has a role in the community. - */ - public Boolean isPrivileged; - - /** - * The URL for the user's avatar. May be null. - */ - public String avatarUrl; - - /** - * Tell whether the user's membership is public. - */ - public Boolean isPublic; - - - /** - * @return the user display name - */ - public String getDisplayname() { - return (null != displayname) ? displayname : userId; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupUsers.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupUsers.java deleted file mode 100644 index 742698ec..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupUsers.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.group; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * This class represents the group users in the server response. - */ -public class GroupUsers implements Serializable { - - public Integer totalUserCountEstimate; - - public List chunk; - - // the server sends some duplicated entries - private List mFilteredUsers; - - /** - * @return the users list - */ - public List getUsers() { - if (null == chunk) { - mFilteredUsers = chunk = new ArrayList<>(); - } else if (null == mFilteredUsers) { - mFilteredUsers = new ArrayList<>(); - - Map map = new HashMap<>(); - - for (GroupUser user : chunk) { - if (null != user.userId) { - map.put(user.userId, user); - } else { - mFilteredUsers.add(user); - } - } - mFilteredUsers.addAll(map.values()); - } - - return mFilteredUsers; - } - - /** - * @return the estimated users count - */ - public int getEstimatedUsersCount() { - if (null == totalUserCountEstimate) { - totalUserCountEstimate = getUsers().size(); - } - - return totalUserCountEstimate; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupsSyncResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupsSyncResponse.java deleted file mode 100644 index 60970bb0..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/GroupsSyncResponse.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.group; - -import java.util.Map; - -/** - * Group sync response - */ -public class GroupsSyncResponse { - /** - * Joined groups: An array of groups ids. - */ - public Map join; - - /** - * Invitations. The groups that the user has been invited to: keys are groups ids. - */ - public Map invite; - - /** - * Left groups. An array of groups ids: the groups that the user has left or been banned from. - */ - public Map leave; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/InvitedGroupSync.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/InvitedGroupSync.java deleted file mode 100644 index 925417c6..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/InvitedGroupSync.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.group; - -import java.io.Serializable; - -/** - * invited group sync - */ -public class InvitedGroupSync { - /** - * The identifier of the inviter. - */ - public String inviter; - - /** - * The group profile. - */ - public GroupSyncProfile profile; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/LeaveGroupParams.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/LeaveGroupParams.java deleted file mode 100644 index 7f720d1a..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/LeaveGroupParams.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.group; - -/** - * The leave group params - */ -public class LeaveGroupParams { -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/UpdatePubliciseParams.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/UpdatePubliciseParams.java deleted file mode 100644 index 1ce14e5f..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/group/UpdatePubliciseParams.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.group; - -/** - * Update the Publicise status - */ -public class UpdatePubliciseParams { - /* - * Whether to show the group on a user’s profile, i.e. this doesn’t affect who gets shown on the group's profile. - */ - public Boolean publicise; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/Credentials.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/Credentials.java deleted file mode 100644 index fb2872fd..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/Credentials.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.login; - -import android.text.TextUtils; - -import org.json.JSONException; -import org.json.JSONObject; - -/** - * The user's getCredentials. - */ -public class Credentials { - public String userId; - public String homeServer; // This is the server name and not a URI, e.g. "matrix.org" - public String accessToken; - public String refreshToken; - public String deviceId; - - public JSONObject toJson() throws JSONException { - JSONObject json = new JSONObject(); - - json.put("user_id", userId); - json.put("home_server", homeServer); - json.put("access_token", accessToken); - json.put("refresh_token", TextUtils.isEmpty(refreshToken) ? JSONObject.NULL : refreshToken); - json.put("device_id", deviceId); - - return json; - } - - public static Credentials fromJson(JSONObject obj) throws JSONException { - Credentials creds = new Credentials(); - creds.userId = obj.getString("user_id"); - creds.homeServer = obj.getString("home_server"); - creds.accessToken = obj.getString("access_token"); - - if (obj.has("device_id")) { - creds.deviceId = obj.getString("device_id"); - } - - // refresh_token is mandatory - if (obj.has("refresh_token")) { - try { - creds.refreshToken = obj.getString("refresh_token"); - } catch (Exception e) { - creds.refreshToken = null; - } - } else { - throw new RuntimeException("refresh_token is required."); - } - - return creds; - } - - @Override - public String toString() { - return "Credentials{" + - "userId='" + userId + '\'' + - ", homeServer='" + homeServer + '\'' + - ", refreshToken.length='" + (refreshToken != null ? refreshToken.length() : "null") + '\'' + - ", accessToken.length='" + (accessToken != null ? accessToken.length() : "null") + '\'' + - '}'; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/LoginFlow.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/LoginFlow.java deleted file mode 100644 index aea8fb71..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/LoginFlow.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.login; - -import java.util.List; - -/** - * A Login flow. - */ -public class LoginFlow implements java.io.Serializable { - public String type; - public List stages; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/LoginFlowResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/LoginFlowResponse.java deleted file mode 100644 index da5f9be9..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/LoginFlowResponse.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.login; - -import java.util.List; - -/** - * Response to a GET /login call with the different login flows. - */ -public class LoginFlowResponse { - public List flows; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/LoginParams.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/LoginParams.java deleted file mode 100644 index 963b56ab..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/LoginParams.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.login; - -/** - * Class to pass parameters to the different login types for /login. - */ -public class LoginParams { - public String type; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/PasswordLoginParams.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/PasswordLoginParams.java deleted file mode 100644 index d0f0d2b9..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/PasswordLoginParams.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.login; - -import android.os.Build; -import android.support.annotation.NonNull; -import android.text.TextUtils; - -import im.vector.matrix.android.internal.legacy.rest.client.LoginRestClient; - -import java.util.HashMap; -import java.util.Map; - -/** - * Object to pass to a /login call of type password. - */ -public class PasswordLoginParams extends LoginParams { - public static final String IDENTIFIER_KEY_TYPE_USER = "m.id.user"; - public static final String IDENTIFIER_KEY_TYPE_THIRD_PARTY = "m.id.thirdparty"; - public static final String IDENTIFIER_KEY_TYPE_PHONE = "m.id.phone"; - - public static final String IDENTIFIER_KEY_TYPE = "type"; - public static final String IDENTIFIER_KEY_MEDIUM = "medium"; - public static final String IDENTIFIER_KEY_ADDRESS = "address"; - public static final String IDENTIFIER_KEY_USER = "user"; - public static final String IDENTIFIER_KEY_COUNTRY = "country"; - public static final String IDENTIFIER_KEY_NUMBER = "number"; - - // identifier parameters - public Map identifier; - - // user name login - public String user; - - // email login - public String address; - public String medium; - - // common - public String password; - - // A display name to assign to the newly-created device - public String initial_device_display_name; - - // The device id, used for e2e encryption - public String device_id; - - /** - * Set login params for username/password - * - * @param username the username - * @param password the password - */ - public void setUserIdentifier(@NonNull final String username, @NonNull final String password) { - identifier = new HashMap<>(); - identifier.put(IDENTIFIER_KEY_TYPE, IDENTIFIER_KEY_TYPE_USER); - identifier.put(IDENTIFIER_KEY_USER, username); - // For backward compatibility - user = username; - - setOtherData(password); - } - - /** - * Set login params for 3pid(except phone number)/password - * - * @param medium 3pid type - * @param address 3pid value - * @param password the password - */ - public void setThirdPartyIdentifier(@NonNull final String medium, @NonNull final String address, @NonNull final String password) { - identifier = new HashMap<>(); - identifier.put(IDENTIFIER_KEY_TYPE, IDENTIFIER_KEY_TYPE_THIRD_PARTY); - identifier.put(IDENTIFIER_KEY_MEDIUM, medium); - identifier.put(IDENTIFIER_KEY_ADDRESS, address); - // For backward compatibility - this.medium = medium; - this.address = address; - - setOtherData(password); - } - - /** - * Set login params for phone number/password - * - * @param phoneNumber the phone number - * @param countryCode the country code - * @param password the password - */ - public void setPhoneIdentifier(@NonNull final String phoneNumber, @NonNull final String countryCode, @NonNull final String password) { - identifier = new HashMap<>(); - identifier.put(IDENTIFIER_KEY_TYPE, IDENTIFIER_KEY_TYPE_PHONE); - identifier.put(IDENTIFIER_KEY_NUMBER, phoneNumber); - identifier.put(IDENTIFIER_KEY_COUNTRY, countryCode); - - setOtherData(password); - } - - /** - * Set basic params - * - * @param password the password - */ - private void setOtherData(@NonNull final String password) { - this.password = password; - type = LoginRestClient.LOGIN_FLOW_TYPE_PASSWORD; - initial_device_display_name = Build.MODEL.trim(); - } - - /** - * Set the device name - * - * @param deviceName the new device name - */ - public void setDeviceName(String deviceName) { - if ((null != deviceName) && !TextUtils.isEmpty(deviceName.trim())) { - initial_device_display_name = deviceName.trim(); - } else { - initial_device_display_name = Build.MODEL.trim(); - } - } - - /** - * Set the device Id - * - * @param deviceId the device id, used for e2e encryption - */ - public void setDeviceId(String deviceId) { - device_id = deviceId; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/RegistrationFlowResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/RegistrationFlowResponse.java deleted file mode 100644 index 8dc490e2..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/RegistrationFlowResponse.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.rest.model.login; - -import java.util.List; -import java.util.Map; - -/** - * Response to a POST /register call with the different flows. - */ -public class RegistrationFlowResponse implements java.io.Serializable { - /** - * The list of stages the client has completed successfully. - */ - public List flows; - - /** - * The list of stages the client has completed successfully. - */ - public List completed; - - /** - * The session identifier that the client must pass back to the home server, if one is provided, - * in subsequent attempts to authenticate in the same API call. - */ - public String session; - - /** - * The information that the client will need to know in order to use a given type of authentication. - * For each login stage type presented, that type may be present as a key in this dictionary. - * For example, the public key of reCAPTCHA stage could be given here. - */ - public Map params; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/RegistrationParams.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/RegistrationParams.java deleted file mode 100644 index b48c4df9..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/RegistrationParams.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.rest.model.login; - -import java.util.Map; - -/** - * Class to pass parameters to the different registration types for /register. - */ -public class RegistrationParams { - // authentification parameters - public Map auth; - - // the account username - public String username; - - // the account password - public String password; - - // With email - public Boolean bind_email; - - // With phone_number - public Boolean bind_msisdn; - - // device name - public String initial_device_display_name; - - // Temporary flag to notify the server that we support msisdn flow. Used to prevent old app - // versions to end up in fallback because the HS returns the msisdn flow which they don't support - public Boolean x_show_msisdn; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/TokenLoginParams.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/TokenLoginParams.java deleted file mode 100644 index dd6bbb3a..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/TokenLoginParams.java +++ /dev/null @@ -1,16 +0,0 @@ -package im.vector.matrix.android.internal.legacy.rest.model.login; - - -public class TokenLoginParams extends LoginParams { - public String user; - public String token; - public String txn_id; - - // A display name to assign to the newly-created device - public String initial_device_display_name; - - - public TokenLoginParams() { - type = "m.login.token"; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/TokenRefreshParams.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/TokenRefreshParams.java deleted file mode 100644 index 9c6b8ce3..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/TokenRefreshParams.java +++ /dev/null @@ -1,7 +0,0 @@ -package im.vector.matrix.android.internal.legacy.rest.model.login; - - -public class TokenRefreshParams { - public String refresh_token; -} - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/TokenRefreshResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/TokenRefreshResponse.java deleted file mode 100644 index 647a55ad..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/login/TokenRefreshResponse.java +++ /dev/null @@ -1,8 +0,0 @@ -package im.vector.matrix.android.internal.legacy.rest.model.login; - - -public class TokenRefreshResponse { - public String access_token; - public String refresh_token; -} - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/AudioMessage.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/AudioMessage.java deleted file mode 100644 index dbab6913..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/AudioMessage.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.rest.model.message; - -public class AudioMessage extends FileMessage { - public AudioMessage() { - msgtype = MSGTYPE_AUDIO; - } -} - - - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/FileInfo.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/FileInfo.java deleted file mode 100644 index 465b6090..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/FileInfo.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.rest.model.message; - -public class FileInfo { - public String mimetype; - public Long size; - - /** - * Make a deep copy. - * - * @return the copy - */ - public FileInfo deepCopy() { - FileInfo copy = new FileInfo(); - copy.mimetype = mimetype; - copy.size = size; - return copy; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/FileMessage.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/FileMessage.java deleted file mode 100644 index 665e867a..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/FileMessage.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.message; - -import android.content.ClipDescription; -import android.text.TextUtils; - -import im.vector.matrix.android.internal.legacy.crypto.MXEncryptedAttachments; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.EncryptedFileInfo; -import im.vector.matrix.android.internal.legacy.util.Log; - -import android.webkit.MimeTypeMap; - -public class FileMessage extends MediaMessage { - private static final String LOG_TAG = FileMessage.class.getSimpleName(); - - public FileInfo info; - public String url; - - // encrypted medias - // url and thumbnailUrl are replaced by their dedicated file - public EncryptedFileInfo file; - - public FileMessage() { - msgtype = MSGTYPE_FILE; - } - - @Override - public String getUrl() { - if (null != url) { - return url; - } else if (null != file) { - return file.url; - } else { - return null; - } - } - - @Override - public void setUrl(MXEncryptedAttachments.EncryptionResult encryptionResult, String contentUrl) { - if (null != encryptionResult) { - file = encryptionResult.mEncryptedFileInfo; - file.url = contentUrl; - url = null; - } else { - url = contentUrl; - } - } - - /** - * Make a deep copy of this VideoMessage. - * - * @return the copy - */ - public FileMessage deepCopy() { - FileMessage copy = new FileMessage(); - copy.msgtype = msgtype; - copy.body = body; - copy.url = url; - - if (null != info) { - copy.info = info.deepCopy(); - } - - if (null != file) { - copy.file = file.deepCopy(); - } - - return copy; - } - - @Override - public String getMimeType() { - if (null != info) { - // the mimetype was not provided or it's invalid - // some android application set the mimetype to text/uri-list - // it should be fixed on application side but we need to patch it on client side. - if ((TextUtils.isEmpty(info.mimetype) || ClipDescription.MIMETYPE_TEXT_URILIST.equals(info.mimetype)) && (body.indexOf('.') > 0)) { - // the body should contain the filename so try to extract the mimetype from the extension - String extension = body.substring(body.lastIndexOf('.') + 1, body.length()); - - try { - info.mimetype = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase()); - } catch (Exception e) { - Log.e(LOG_TAG, "## getMimeType() : getMimeTypeFromExtensionfailed " + e.getMessage(), e); - } - } - - if (TextUtils.isEmpty(info.mimetype)) { - info.mimetype = "application/octet-stream"; - } - - return info.mimetype; - } else { - return null; - } - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/ImageInfo.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/ImageInfo.java deleted file mode 100644 index 15c57ff8..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/ImageInfo.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.rest.model.message; - -import im.vector.matrix.android.internal.legacy.rest.model.crypto.EncryptedFileInfo; - -public class ImageInfo { - public String mimetype; - public Integer w; - public Integer h; - public Long size; - public Integer rotation; - - // ExifInterface.ORIENTATION_XX values - public Integer orientation; - - public ThumbnailInfo thumbnailInfo; - public String thumbnailUrl; - public EncryptedFileInfo thumbnail_file; - - /** - * Make a deep copy. - * - * @return the copy - */ - public ImageInfo deepCopy() { - ImageInfo copy = new ImageInfo(); - copy.mimetype = mimetype; - copy.w = w; - copy.h = h; - copy.size = size; - copy.rotation = rotation; - copy.orientation = orientation; - - if (null != thumbnail_file) { - copy.thumbnail_file = thumbnail_file.deepCopy(); - } - - copy.thumbnailUrl = thumbnailUrl; - - if (null != thumbnailInfo) { - copy.thumbnailInfo = thumbnailInfo.deepCopy(); - } - - return copy; - } -} - - - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/ImageMessage.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/ImageMessage.java deleted file mode 100644 index d42145ff..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/ImageMessage.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.rest.model.message; - -import android.media.ExifInterface; - -import im.vector.matrix.android.internal.legacy.crypto.MXEncryptedAttachments; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.EncryptedFileInfo; - -public class ImageMessage extends MediaMessage { - public ImageInfo info; - public String url; - - // encrypted medias - // url and thumbnailUrl are replaced by their dedicated file - public EncryptedFileInfo file; - - public ImageMessage() { - msgtype = MSGTYPE_IMAGE; - } - - /** - * Make a deep copy of this ImageMessage. - * FIXME Remove this? - * @return the copy - */ - public ImageMessage deepCopy() { - ImageMessage copy = new ImageMessage(); - copy.msgtype = msgtype; - copy.body = body; - copy.url = url; - - if (null != file) { - copy.file = file.deepCopy(); - } - - return copy; - } - - @Override - public String getUrl() { - if (null != url) { - return url; - } else if (null != file) { - return file.url; - } else { - return null; - } - } - - @Override - public void setUrl(MXEncryptedAttachments.EncryptionResult encryptionResult, String contentUrl) { - if (null != encryptionResult) { - file = encryptionResult.mEncryptedFileInfo; - file.url = contentUrl; - url = null; - } else { - url = contentUrl; - } - } - - @Override - public String getThumbnailUrl() { - if (null != info) { - if (null != info.thumbnail_file) { - return info.thumbnail_file.url; - } else { - return info.thumbnailUrl; - } - } - return null; - } - - @Override - public void setThumbnailUrl(MXEncryptedAttachments.EncryptionResult encryptionResult, String url) { - if (null != encryptionResult) { - info.thumbnail_file = encryptionResult.mEncryptedFileInfo; - info.thumbnail_file.url = url; - info.thumbnailUrl = null; - } else { - info.thumbnailUrl = url; - } - } - - @Override - public String getMimeType() { - if (null != file) { - return file.mimetype; - } else if (null != info) { - return info.mimetype; - } else { - return null; - } - } - - /** - * @return the rotation angle. Integer.MAX_VALUE if not defined. - */ - public int getRotation() { - if ((null != info) && (null != info.rotation)) { - return info.rotation; - } else { - return Integer.MAX_VALUE; - } - } - - /** - * @return the image orientation. ExifInterface.ORIENTATION_UNDEFINED if not defined. - */ - public int getOrientation() { - if ((null != info) && (null != info.orientation)) { - return info.orientation; - } else { - return ExifInterface.ORIENTATION_UNDEFINED; - } - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/LocationMessage.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/LocationMessage.java deleted file mode 100644 index d6b96b03..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/LocationMessage.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.rest.model.message; - -import android.net.Uri; - -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.io.File; - -public class LocationMessage extends Message { - private static final String LOG_TAG = "LocationMessage"; - public ThumbnailInfo thumbnail_info; - public String geo_uri; - public String thumbnail_url; - - public LocationMessage() { - msgtype = MSGTYPE_LOCATION; - } - - /** - * Make a deep copy - * @return the copy - */ - public LocationMessage deepCopy() { - LocationMessage copy = new LocationMessage(); - copy.msgtype = msgtype; - copy.body = body; - copy.geo_uri = geo_uri; - copy.thumbnail_url = thumbnail_url; - - if (null != thumbnail_info) { - copy.thumbnail_info = thumbnail_info.deepCopy(); - } - - return copy; - } - - public boolean isLocalThumbnailContent() { - return (null != thumbnail_url) && (thumbnail_url.startsWith("file://")); - } - - /** - * Checks if the media Urls are still valid. - * The media Urls could define a file path. - * They could have been deleted after a media cache cleaning. - */ - public void checkMediaUrls() { - if ((thumbnail_url != null) && thumbnail_url.startsWith("file://")) { - try { - File file = new File(Uri.parse(thumbnail_url).getPath()); - - if (!file.exists()) { - thumbnail_url = null; - } - } catch (Exception e) { - Log.e(LOG_TAG, "## checkMediaUrls() failed " + e.getMessage(), e); - } - } - } -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/MediaMessage.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/MediaMessage.java deleted file mode 100644 index 43367414..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/MediaMessage.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.rest.model.message; - -import android.net.Uri; - -import im.vector.matrix.android.internal.legacy.crypto.MXEncryptedAttachments; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.io.File; - -public class MediaMessage extends Message { - public static final String LOG_TAG = MediaMessage.class.getSimpleName(); - - /** - * @return the media URL - */ - public String getUrl() { - return null; - } - - - public void setUrl(MXEncryptedAttachments.EncryptionResult encryptionResult, String url) { - } - - /** - * @return the thumbnail url - */ - public String getThumbnailUrl() { - return null; - } - - public void setThumbnailUrl(MXEncryptedAttachments.EncryptionResult encryptionResult, String url) { - } - - /** - * @return true if the thumbnail is a file url - */ - public boolean isThumbnailLocalContent() { - String thumbUrl = getThumbnailUrl(); - return (null != thumbUrl) && thumbUrl.startsWith("file://"); - } - - /** - * @return true if the media url is a file one. - */ - public boolean isLocalContent() { - String url = getUrl(); - return (null != url) && url.startsWith("file://"); - } - - /** - * @return The image mimetype. null is not defined. - */ - public String getMimeType() { - return null; - } - - /** - * Checks if the media Urls are still valid. - * The media Urls could define a file path. - * They could have been deleted after a media cache cleaning. - */ - public void checkMediaUrls() { - String thumbUrl = getThumbnailUrl(); - - if ((null != thumbUrl) && thumbUrl.startsWith("file://")) { - try { - File file = new File(Uri.parse(thumbUrl).getPath()); - - if (!file.exists()) { - setThumbnailUrl(null, null); - } - } catch (Exception e) { - Log.e(LOG_TAG, "## checkMediaUrls() failed" + e.getMessage(), e); - } - } - - String url = getUrl(); - - if ((url != null) && url.startsWith("file://")) { - try { - File file = new File(Uri.parse(url).getPath()); - - if (!file.exists()) { - setUrl(null, null); - } - } catch (Exception e) { - Log.e(LOG_TAG, "## checkMediaUrls() failed" + e.getMessage(), e); - } - } - } -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/Message.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/Message.java deleted file mode 100644 index 0c517cc0..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/Message.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.message; - -import com.google.gson.annotations.SerializedName; - -public class Message { - public static final String MSGTYPE_TEXT = "m.text"; - public static final String MSGTYPE_EMOTE = "m.emote"; - public static final String MSGTYPE_NOTICE = "m.notice"; - public static final String MSGTYPE_IMAGE = "m.image"; - public static final String MSGTYPE_AUDIO = "m.audio"; - public static final String MSGTYPE_VIDEO = "m.video"; - public static final String MSGTYPE_LOCATION = "m.location"; - public static final String MSGTYPE_FILE = "m.file"; - public static final String FORMAT_MATRIX_HTML = "org.matrix.custom.html"; - - // Add, in local, a fake message type in order to StickerMessage can inherit Message class - // Because sticker isn't a message type but a event type without msgtype field - public static final String MSGTYPE_STICKER_LOCAL = "org.matrix.android.sdk.sticker"; - - public String msgtype; - public String body; - - public String format; - public String formatted_body; - - @SerializedName("m.relates_to") - public RelatesTo relatesTo; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/RelatesTo.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/RelatesTo.java deleted file mode 100644 index 8a05528e..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/RelatesTo.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.message; - -import com.google.gson.annotations.SerializedName; - -import java.util.Map; - -public class RelatesTo { - @SerializedName("m.in_reply_to") - public Map dict; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/StickerJsonMessage.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/StickerJsonMessage.java deleted file mode 100644 index e9dd1c82..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/StickerJsonMessage.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.message; - - -// It's just an intermediate object to create a StickerMessage from a m.sticker event type. -public class StickerJsonMessage { - - public final String msgtype = Message.MSGTYPE_STICKER_LOCAL; - public String body; - public String url; - public String format; - public ImageInfo info; - -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/StickerMessage.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/StickerMessage.java deleted file mode 100644 index e52fac6f..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/StickerMessage.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.message; - - -public class StickerMessage extends ImageMessage { - - public StickerMessage() { - msgtype = MSGTYPE_STICKER_LOCAL; - } - - public StickerMessage(StickerJsonMessage stickerJsonMessage) { - this(); - info = stickerJsonMessage.info; - url = stickerJsonMessage.url; - body = stickerJsonMessage.body; - format = stickerJsonMessage.format; - } - - /** - * Make a deep copy of this StickerMessage. - * - * @return the copy - */ - public StickerMessage deepCopy() { - StickerMessage copy = new StickerMessage(); - copy.info = info; - copy.url = url; - copy.body = body; - copy.format = format; - - if (null != file) { - copy.file = file.deepCopy(); - } - - return copy; - } -} - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/ThumbnailInfo.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/ThumbnailInfo.java deleted file mode 100644 index 8fc3c8ad..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/ThumbnailInfo.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.message; - -public class ThumbnailInfo { - public Integer w; - public Integer h; - public Long size; - public String mimetype; - - /** - * Make a deep copy of this VideoMessage. - * - * @return the copy - */ - public ThumbnailInfo deepCopy() { - ThumbnailInfo copy = new ThumbnailInfo(); - - copy.w = w; - copy.h = h; - copy.size = size; - copy.mimetype = mimetype; - - return copy; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/VideoInfo.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/VideoInfo.java deleted file mode 100644 index 62770fe1..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/VideoInfo.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.rest.model.message; - -import im.vector.matrix.android.internal.legacy.rest.model.crypto.EncryptedFileInfo; - -public class VideoInfo { - public Integer h; - public Integer w; - public String mimetype; - public Long duration; - public Long size; - public String thumbnail_url; - public ThumbnailInfo thumbnail_info; - - public EncryptedFileInfo thumbnail_file; - - /** - * Make a deep copy. - * - * @return the copy - */ - public VideoInfo deepCopy() { - VideoInfo copy = new VideoInfo(); - copy.h = h; - copy.w = w; - copy.mimetype = mimetype; - copy.duration = duration; - copy.thumbnail_url = thumbnail_url; - - if (null != thumbnail_info) { - copy.thumbnail_info = thumbnail_info.deepCopy(); - } - - if (null != thumbnail_file) { - copy.thumbnail_file = thumbnail_file.deepCopy(); - } - - return copy; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/VideoMessage.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/VideoMessage.java deleted file mode 100644 index f6d3f841..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/message/VideoMessage.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.rest.model.message; - -import im.vector.matrix.android.internal.legacy.crypto.MXEncryptedAttachments; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.EncryptedFileInfo; - -public class VideoMessage extends MediaMessage { - - public VideoInfo info; - public String url; - - // encrypted medias - // url and thumbnailUrl are replaced by their dedicated file - public EncryptedFileInfo file; - - public VideoMessage() { - msgtype = MSGTYPE_VIDEO; - } - - @Override - public String getUrl() { - if (null != url) { - return url; - } else if (null != file) { - return file.url; - } else { - return null; - } - } - - @Override - public void setUrl(MXEncryptedAttachments.EncryptionResult encryptionResult, String contentUrl) { - if (null != encryptionResult) { - file = encryptionResult.mEncryptedFileInfo; - file.url = contentUrl; - url = null; - } else { - url = contentUrl; - } - } - - @Override - public String getThumbnailUrl() { - if ((null != info) && (null != info.thumbnail_url)) { - return info.thumbnail_url; - } else if ((null != info) && (null != info.thumbnail_file)) { - return info.thumbnail_file.url; - } - - return null; - } - - @Override - public void setThumbnailUrl(MXEncryptedAttachments.EncryptionResult encryptionResult, String url) { - if (null != encryptionResult) { - info.thumbnail_file = encryptionResult.mEncryptedFileInfo; - info.thumbnail_file.url = url; - info.thumbnail_url = null; - } else { - info.thumbnail_url = url; - } - } - - /** - * Make a deep copy of this VideoMessage. - * - * @return the copy - */ - public VideoMessage deepCopy() { - VideoMessage copy = new VideoMessage(); - copy.url = url; - copy.msgtype = msgtype; - copy.body = body; - - if (null != info) { - copy.info = info.deepCopy(); - } - - if (null != file) { - copy.file = file.deepCopy(); - } - - return copy; - } - - @Override - public String getMimeType() { - if (null != info) { - return info.mimetype; - } else { - return null; - } - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/AccountThreePidsResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/AccountThreePidsResponse.java deleted file mode 100644 index 60f8e879..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/AccountThreePidsResponse.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.pid; - -import java.util.List; - -/** - * Class representing the ThreePids response - */ -public class AccountThreePidsResponse { - public List threepids; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/AddThreePidsParams.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/AddThreePidsParams.java deleted file mode 100644 index 1ab806a4..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/AddThreePidsParams.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.pid; - -import im.vector.matrix.android.internal.legacy.rest.model.ThreePidCreds; - -/** - * Parameters to add a 3Pids to an user - */ -public class AddThreePidsParams { - - // the 3rd party id getCredentials - public ThreePidCreds three_pid_creds; - - // true when the email has been binded. - public Boolean bind; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/DeleteDeviceAuth.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/DeleteDeviceAuth.java deleted file mode 100644 index c62e334f..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/DeleteDeviceAuth.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.rest.model.pid; - -/** - * This class provides the - */ -public class DeleteDeviceAuth { - - // device device session id - public String session; - - // registration information - public String type; - public String user; - public String password; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/DeleteDeviceParams.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/DeleteDeviceParams.java deleted file mode 100644 index 899aa9e8..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/DeleteDeviceParams.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.rest.model.pid; - -/** - * This class provides the parameter to delete a device - */ -public class DeleteDeviceParams { - public DeleteDeviceAuth auth; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/DeleteThreePidParams.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/DeleteThreePidParams.java deleted file mode 100644 index d5977dc9..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/DeleteThreePidParams.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.rest.model.pid; - -/** - * Parameters to delete a 3Pid of a user - */ -public class DeleteThreePidParams { - - // the 3pid medium (email, phone number, etc.) - public String medium; - - // the msisdn that will be deleted from the account - public String address; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/Invite3Pid.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/Invite3Pid.java deleted file mode 100755 index e28e7152..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/Invite3Pid.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.pid; - -/** - * - */ -public class Invite3Pid { - /** - * Required. - * The hostname+port of the identity server which should be used for third party identifier lookups. - */ - public String id_server; - - /** - * Required. - * The kind of address being passed in the address field, for example email. - */ - public String medium; - - /** - * Required. - * The invitee's third party identifier. - */ - public String address; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/PidResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/PidResponse.java deleted file mode 100755 index c4766323..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/PidResponse.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.pid; - -public class PidResponse { - public String mxid; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/RoomThirdPartyInvite.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/RoomThirdPartyInvite.java deleted file mode 100644 index 6e246d10..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/RoomThirdPartyInvite.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.rest.model.pid; - -/** - * Class representing a room member: a user with membership information. - */ -public class RoomThirdPartyInvite implements java.io.Serializable { - - /** - * The user display name as provided by the home sever. - */ - public String display_name; - - /** - * The token generated by the identity server. - */ - public String token; - - // the event used to build this class - private String mOriginalEventId = null; - - /** - * @return a RoomThirdPartyInvite deep copy. - */ - public RoomThirdPartyInvite deepCopy() { - RoomThirdPartyInvite copy = new RoomThirdPartyInvite(); - copy.display_name = display_name; - copy.token = token; - copy.mOriginalEventId = mOriginalEventId; - return copy; - } - - /** - * Set the original used to create this class - * - * @param eventId the event id - */ - public void setOriginalEventid(String eventId) { - mOriginalEventId = eventId; - } - - /** - * Provides the even used to create this class - * - * @return the event uses to create this class - */ - public String getOriginalEventId() { - return mOriginalEventId; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/ThirdPartyIdentifier.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/ThirdPartyIdentifier.java deleted file mode 100755 index dc332830..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/ThirdPartyIdentifier.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.rest.model.pid; - -import java.io.Serializable; - -public class ThirdPartyIdentifier implements Serializable { - /** - * The medium of the third party identifier (ThreePid.MEDIUM_XXX) - */ - public String medium; - - /** - * The third party identifier address. - */ - public String address; - - /** - * The timestamp in milliseconds when this 3PID has been validated. - * Define as Object because it should be Long and it is a Double. - * So, it might change. - */ - public Object validatedAt; - - /** - * The timestamp in milliseconds when this 3PID has been added to the user account. - * Define as Object because it should be Long and it is a Double. - * So, it might change. - */ - public Object addedAt; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/ThirdPartyProtocol.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/ThirdPartyProtocol.java deleted file mode 100755 index 530d752c..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/ThirdPartyProtocol.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.rest.model.pid; - -import java.util.List; -import java.util.Map; - -/** - * This class describes the third party server protocols. - */ -public class ThirdPartyProtocol { - // the user fields (domain, nick, username...) - public List userFields; - - // the location fields (domain, channels, room...) - public List locationFields; - - // the field types - public Map> fieldTypes; - - // the protocol instance - public List instances; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/ThirdPartyProtocolInstance.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/ThirdPartyProtocolInstance.java deleted file mode 100755 index a7197098..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/ThirdPartyProtocolInstance.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.rest.model.pid; - -import java.io.Serializable; -import java.util.Map; - -/** - * This class describes a third party protocol instance - */ -public class ThirdPartyProtocolInstance implements Serializable { - - // the network identifier - public String networkId; - - // the fields (domain...) - public Map fields; - - // the instance id - public String instanceId; - - // the description - public String desc; - - // the dedicated bot - public String botUserId; - - // the icon URL - public String icon; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/ThreePid.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/ThreePid.java deleted file mode 100755 index 617ac6f3..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/pid/ThreePid.java +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.pid; - -import android.content.Context; -import android.text.TextUtils; - -import im.vector.matrix.android.R; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.client.ProfileRestClient; -import im.vector.matrix.android.internal.legacy.rest.client.ThirdPidRestClient; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.rest.model.RequestEmailValidationResponse; -import im.vector.matrix.android.internal.legacy.rest.model.RequestPhoneNumberValidationResponse; - -import java.util.UUID; - -/** - * 3 pid - */ -public class ThreePid implements java.io.Serializable { - /** - * Types of third party media. - * The list is not exhaustive and depends on the Identity server capabilities. - */ - public static final String MEDIUM_EMAIL = "email"; - public static final String MEDIUM_MSISDN = "msisdn"; - - // state - public static final int AUTH_STATE_TOKEN_UNKNOWN = 0; - public static final int AUTH_STATE_TOKEN_REQUESTED = 1; - public static final int AUTH_STATE_TOKEN_RECEIVED = 2; - public static final int AUTH_STATE_TOKEN_SUBMITTED = 3; - public static final int AUTH_STATE_TOKEN_AUTHENTIFICATED = 4; - - /** - * Types of third party media. - */ - public String medium; - - /** - * The email of the user - * Used when MEDIUM_EMAIL - */ - public String emailAddress; - - /** - * The phone number of the user - * Used when MEDIUM_MSISDN - */ - public String phoneNumber; - - /** - * The country of the user - * Usedwhen MEDIUM_MSISDN - */ - public String country; - - /** - * The current client secret key used during email validation. - */ - public String clientSecret; - - /** - * The current session identifier during email validation. - */ - public String sid; - - /** - * The number of attempts - */ - public int sendAttempt; - - /** - * Current validation state (AUTH_STATE_XXX) - */ - private int mValidationState; - - /** - * Two params constructors (MEDIUM_EMAIL) - * - * @param emailAddress the email address. - * @param medium the identifier medium, MEDIUM_EMAIL in that case - */ - public ThreePid(String emailAddress, String medium) { - this.medium = medium; - this.emailAddress = emailAddress; - - if (TextUtils.equals(MEDIUM_EMAIL, medium) && !TextUtils.isEmpty(emailAddress)) { - this.emailAddress = emailAddress.toLowerCase(); - } - - clientSecret = UUID.randomUUID().toString(); - } - - /** - * Build a ThreePid with the given phone number and country (MEDIUM_MSISDN) - * - * @param phoneNumber the phone number (national or international format) - * @param country country code of the phone number (can be empty if phone number has international format and starts by "+") - * @param medium the identifier medium, MEDIUM_MSISDN in that case - */ - public ThreePid(String phoneNumber, String country, String medium) { - this.medium = medium; - this.phoneNumber = phoneNumber; - this.country = country == null ? "" : country.toUpperCase(); - - clientSecret = UUID.randomUUID().toString(); - } - - /** - * Clear the validation parameters - */ - private void resetValidationParameters() { - mValidationState = AUTH_STATE_TOKEN_UNKNOWN; - - clientSecret = UUID.randomUUID().toString(); - sendAttempt = 1; - sid = null; - } - - /** - * Request an email validation token. - * - * @param restClient the rest client to use. - * @param nextLink the nextLink - * @param isDuringRegistration true if it is added during a registration - * @param callback the callback when the operation is done - */ - public void requestEmailValidationToken(final ProfileRestClient restClient, - final String nextLink, - final boolean isDuringRegistration, - final ApiCallback callback) { - // sanity check - if (null != restClient && mValidationState != AUTH_STATE_TOKEN_REQUESTED) { - - if (mValidationState != AUTH_STATE_TOKEN_UNKNOWN) { - resetValidationParameters(); - } - - mValidationState = AUTH_STATE_TOKEN_REQUESTED; - restClient.requestEmailValidationToken(emailAddress, clientSecret, sendAttempt, nextLink, isDuringRegistration, - new ApiCallback() { - - @Override - public void onSuccess(RequestEmailValidationResponse requestEmailValidationResponse) { - - if (TextUtils.equals(requestEmailValidationResponse.clientSecret, clientSecret)) { - mValidationState = AUTH_STATE_TOKEN_RECEIVED; - sid = requestEmailValidationResponse.sid; - callback.onSuccess(null); - } - } - - private void commonError() { - sendAttempt++; - mValidationState = AUTH_STATE_TOKEN_UNKNOWN; - } - - @Override - public void onNetworkError(Exception e) { - commonError(); - callback.onNetworkError(e); - } - - @Override - public void onMatrixError(MatrixError e) { - commonError(); - callback.onMatrixError(e); - } - - @Override - public void onUnexpectedError(Exception e) { - commonError(); - callback.onUnexpectedError(e); - } - }); - - } - } - - /** - * Request a phone number validation token. - * - * @param restClient the rest client to use. - * @param isDuringRegistration true if it is added during a registration - * @param callback the callback when the operation is done - */ - public void requestPhoneNumberValidationToken(final ProfileRestClient restClient, final boolean isDuringRegistration, - final ApiCallback callback) { - // sanity check - if ((null != restClient) && (mValidationState != AUTH_STATE_TOKEN_REQUESTED)) { - - if (mValidationState != AUTH_STATE_TOKEN_UNKNOWN) { - resetValidationParameters(); - } - - mValidationState = AUTH_STATE_TOKEN_REQUESTED; - - restClient.requestPhoneNumberValidationToken(phoneNumber, country, clientSecret, sendAttempt, isDuringRegistration, - new ApiCallback() { - - @Override - public void onSuccess(RequestPhoneNumberValidationResponse requestPhoneNumberValidationResponse) { - - if (TextUtils.equals(requestPhoneNumberValidationResponse.clientSecret, clientSecret)) { - mValidationState = AUTH_STATE_TOKEN_RECEIVED; - sid = requestPhoneNumberValidationResponse.sid; - callback.onSuccess(null); - } - } - - private void commonError() { - sendAttempt++; - mValidationState = AUTH_STATE_TOKEN_UNKNOWN; - } - - @Override - public void onNetworkError(Exception e) { - commonError(); - callback.onNetworkError(e); - } - - @Override - public void onMatrixError(MatrixError e) { - commonError(); - callback.onMatrixError(e); - } - - @Override - public void onUnexpectedError(Exception e) { - commonError(); - callback.onUnexpectedError(e); - } - }); - } - } - - /** - * Request the ownership validation of an email address or a phone number previously set - * by {@link #requestEmailValidationToken(ProfileRestClient, String, boolean, ApiCallback)} - * - * @param restClient REST client - * @param token the token generated by the requestEmailValidationToken or requestPhoneNumberValidationToken call - * @param clientSecret the client secret which was supplied in the requestEmailValidationToken or requestPhoneNumberValidationToken call - * @param sid the sid for the session - * @param respCallback asynchronous callback response - */ - public void submitValidationToken(final ThirdPidRestClient restClient, final String token, final String clientSecret, - final String sid, final ApiCallback respCallback) { - // sanity check - if (null != restClient) { - restClient.submitValidationToken(medium, token, clientSecret, sid, respCallback); - } - } - - /** - * Get the friendly name of the medium - * - * @param medium medium of the 3pid - * @param context the context - * @return friendly name of the medium - */ - public static String getMediumFriendlyName(final String medium, final Context context) { - String mediumFriendlyName = ""; - switch (medium) { - case MEDIUM_EMAIL: - mediumFriendlyName = context.getString(R.string.medium_email); - break; - case MEDIUM_MSISDN: - mediumFriendlyName = context.getString(R.string.medium_phone_number); - break; - } - - return mediumFriendlyName; - } - -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/publicroom/PublicRoom.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/publicroom/PublicRoom.java deleted file mode 100644 index 29219cba..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/publicroom/PublicRoom.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.publicroom; - -import com.google.gson.annotations.SerializedName; - -import java.util.List; - -/** - * Class representing the objects returned by /publicRooms call. - */ -public class PublicRoom { - - public List aliases; - - @SerializedName("canonical_alias") - public String canonicalAlias; - - public String name; - - // number of members which have joined the room (the members list is not provided) - @SerializedName("num_joined_members") - public int numJoinedMembers; - - @SerializedName("room_id") - public String roomId; - - public String topic; - - // true when the room history is visible (room preview) - @SerializedName("world_readable") - public boolean worldReadable; - - // a guest can join the room - @SerializedName("guest_can_join") - public boolean guestCanJoin; - - @SerializedName("avatar_url") - public String avatarUrl; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/publicroom/PublicRoomsFilter.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/publicroom/PublicRoomsFilter.java deleted file mode 100644 index 65a114bc..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/publicroom/PublicRoomsFilter.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.publicroom; - -/** - * Class to define a filter to retrieve public rooms - */ -public class PublicRoomsFilter { - /** - * String to search for - **/ - public String generic_search_term; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/publicroom/PublicRoomsParams.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/publicroom/PublicRoomsParams.java deleted file mode 100644 index 5f5fe88c..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/publicroom/PublicRoomsParams.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.rest.model.publicroom; - -/** - * Class to pass parameters to get the public rooms list - */ -public class PublicRoomsParams { - /** - * The third party instance id - */ - public String thirdPartyInstanceId; - - /** - * Tell if the query must be done in all the connected networks. - */ - public boolean includeAllNetworks; - - /** - * Maximum number of entries to return - **/ - public Integer limit; - - /** - * token to paginate from - **/ - public String since; - - /** - * Filter parameters - **/ - public PublicRoomsFilter filter; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/publicroom/PublicRoomsResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/publicroom/PublicRoomsResponse.java deleted file mode 100644 index 6f76ae75..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/publicroom/PublicRoomsResponse.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.publicroom; - -import java.util.List; - -/** - * Class representing the public rooms request response - */ -public class PublicRoomsResponse { - /** - * token to forward paginate - **/ - public String next_batch; - - /** - * token to back paginate - **/ - public String prev_batch; - - /** - * public rooms list - **/ - public List chunk; - - /** - * number of unfiltered existing rooms - **/ - public Integer total_room_count_estimate; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchCategories.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchCategories.java deleted file mode 100644 index b344c9e6..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchCategories.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.rest.model.search; - -/** - * subclass representing a search API response - */ -public class SearchCategories { - - /** - * Mapping of category name to search criteria. - */ - public SearchRoomEventResults roomEvents; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchEventContext.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchEventContext.java deleted file mode 100644 index baab968d..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchEventContext.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.search; - -import im.vector.matrix.android.internal.legacy.rest.model.Event; - -import java.util.List; -import java.util.Map; - -/** - * subclass representing a search API response - */ -public class SearchEventContext { - /** - * Pagination token for the start of the chunk. - */ - public String start; - - /** - * Pagination token for the end of the chunk. - */ - public String end; - - /** - * Events just before the result. - */ - public List eventsBefore; - - /** - * Events just after the result. - */ - public List eventsAfter; - - /** - * The historic profile information of the users that sent the events returned. - * The key is the user id, the value the user profile. - */ - public Map profileInfo; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchGroup.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchGroup.java deleted file mode 100644 index 50902935..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchGroup.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.search; - -import java.util.Map; - -/** - * subclass representing a search API response - */ -public class SearchGroup { - /** - * Total number of results found. - * The key is "room_id" (TODO_SEARCH) , the value the group. - */ - public Map group; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchGroupContent.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchGroupContent.java deleted file mode 100644 index 09bc8b79..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchGroupContent.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.rest.model.search; - -import java.util.List; - -/** - * subclass representing a search API response - */ -public class SearchGroupContent { - /** - * Which results are in this group. - */ - public List results; - - /** - * Key that can be used to order different groups. - */ - public Integer order; - - /** - * Token that can be used to get the next batch of results in the group, if exists. - */ - public String nextBatch; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchParams.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchParams.java deleted file mode 100644 index 58f0eb63..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchParams.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.search; - -import java.util.Map; - -/** - * Class representing a search parameters - */ -public class SearchParams { - // the search categories - public Map search_categories; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchResponse.java deleted file mode 100644 index a416e10f..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchResponse.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.rest.model.search; - -/** - * subclass representing a search API response - */ -public class SearchResponse { - - /** - * Categories to search in and their criteria.. - */ - public SearchCategories searchCategories; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchResult.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchResult.java deleted file mode 100644 index db58a9ef..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchResult.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.rest.model.search; - -import im.vector.matrix.android.internal.legacy.rest.model.Event; - -/** - * subclass representing a search API response - */ -public class SearchResult { - - /** - * The event that matched. - */ - public Event result; - - /** - * A number that describes how closely this result matches the search. Higher is closer. - */ - public Double rank; - - /** - * Context for result, if requested. - */ - public SearchEventContext context; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchRoomEventCategoryParams.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchRoomEventCategoryParams.java deleted file mode 100644 index eb03ab12..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchRoomEventCategoryParams.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.search; - -import java.util.Map; - -/** - * Class representing the room events search category parameters - */ -public class SearchRoomEventCategoryParams { - // the searched text - public String search_term; - - // the sort order - public String order_by; - - // the event context - public Map event_context; - - // the search filters - public Map filter; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchRoomEventResults.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchRoomEventResults.java deleted file mode 100644 index 180b547a..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchRoomEventResults.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.search; - -import im.vector.matrix.android.internal.legacy.rest.model.Event; - -import java.util.List; -import java.util.Map; - -/** - * Class representing a search API response - */ -public class SearchRoomEventResults { - /** - * Total number of results found. - */ - public Integer count; - - /** - * List of results in the requested order. - */ - public List results; - - /** - * The current state for every room in the results. - * This is included if the request had the include_state key set with a value of true. - * The key is the roomId, the value its state. (TODO_SEARCH: right?) - */ - public Map> state; - - /** - * Any groups that were requested. - * The key is the group id (TODO_SEARCH). - */ - public Map groups; - - /** - * Token that can be used to get the next batch of results in the group, if exists. - */ - public String nextBatch; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchUserProfile.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchUserProfile.java deleted file mode 100644 index f439e328..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchUserProfile.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2016 OpenMarket 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.matrix.android.internal.legacy.rest.model.search; - -/** - * subclass representing a search API response - */ -public class SearchUserProfile { - /** - * The avatar URL for this user, if any. - */ - public String avatarUrl; - - /** - * The display name for this user, if any. - */ - public String displayName; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchUsersParams.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchUsersParams.java deleted file mode 100644 index 05d76a52..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchUsersParams.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.rest.model.search; - -/** - * Class representing an user search parameters - */ -public class SearchUsersParams { - // the searched term - public String search_term; - - // set a limit to the request response - public Integer limit; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchUsersRequestResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchUsersRequestResponse.java deleted file mode 100644 index 7ff7435a..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchUsersRequestResponse.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.rest.model.search; - -import java.util.List; - -/** - * Class representing an users search response - */ -public class SearchUsersRequestResponse { - - // cannot use org.matrix.androidsdk.rest.model.User - // because the display name does not have the same syntax - public class User { - public String user_id; - public String display_name; - public String avatar_url; - } - - // indicates if the result list has been truncated by the limit. - public Boolean limited; - - // set a limit to the request response - public List results; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchUsersResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchUsersResponse.java deleted file mode 100644 index 94f7af7e..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/search/SearchUsersResponse.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.rest.model.search; - -import im.vector.matrix.android.internal.legacy.rest.model.User; - -import java.util.List; - -/** - * Class representing an users search response - */ -public class SearchUsersResponse { - - // indicates if the result list has been truncated by the limit. - public Boolean limited; - - // set a limit to the request response - public List results; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/DeviceInfo.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/DeviceInfo.java deleted file mode 100644 index 625d804d..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/DeviceInfo.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.sync; - -import im.vector.matrix.android.internal.legacy.data.comparator.Comparators; -import im.vector.matrix.android.internal.legacy.interfaces.DatedObject; - -import java.util.Collections; -import java.util.List; - -/** - * This class describes the device information - */ -public class DeviceInfo implements DatedObject { - /** - * The owner user id - */ - public String user_id; - - /** - * The device id - */ - public String device_id; - - /** - * The device display name - */ - public String display_name; - - /** - * The last time this device has been seen. - */ - public long last_seen_ts = 0; - - /** - * The last ip address - */ - public String last_seen_ip; - - @Override - public long getDate() { - return last_seen_ts; - } - - /** - * Sort a devices list by their presences from the most recent to the oldest one. - * - * @param deviceInfos the deviceinfo list - */ - public static void sortByLastSeen(List deviceInfos) { - if (null != deviceInfos) { - Collections.sort(deviceInfos, Comparators.descComparator); - } - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/DeviceListResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/DeviceListResponse.java deleted file mode 100644 index 8a4b0e68..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/DeviceListResponse.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2017 Vector Creations 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.matrix.android.internal.legacy.rest.model.sync; - -import java.util.List; - -/** - * This class describes the device list response from a sync request - */ -public class DeviceListResponse { - // user ids list which have new crypto devices - public List changed; - - // List of user ids who are no more tracked. - public List left; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/DeviceOneTimeKeysCountSyncResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/DeviceOneTimeKeysCountSyncResponse.java deleted file mode 100644 index f336148b..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/DeviceOneTimeKeysCountSyncResponse.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.sync; - -public class DeviceOneTimeKeysCountSyncResponse { - - public Integer signed_curve25519; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/DevicesListResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/DevicesListResponse.java deleted file mode 100644 index d0bf1dba..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/DevicesListResponse.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.rest.model.sync; - -import java.util.List; - -/** - * This class describes the - */ -public class DevicesListResponse { - public List devices; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/InvitedRoomSync.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/InvitedRoomSync.java deleted file mode 100644 index 9e661080..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/InvitedRoomSync.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.sync; - -import com.google.gson.annotations.SerializedName; - -// InvitedRoomSync represents a room invitation during server sync v2. -public class InvitedRoomSync { - - /** - * The state of a room that the user has been invited to. These state events may only have the 'sender', 'type', 'state_key' - * and 'content' keys present. These events do not replace any state that the client already has for the room, for example if - * the client has archived the room. Instead the client should keep two separate copies of the state: the one from the 'invite_state' - * and one from the archived 'state'. If the client joins the room then the current state will be given as a delta against the - * archived 'state' not the 'invite_state'. - */ - @SerializedName("invite_state") - public RoomInviteState inviteState; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/PresenceSyncResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/PresenceSyncResponse.java deleted file mode 100644 index caf4d951..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/PresenceSyncResponse.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.sync; - -import im.vector.matrix.android.internal.legacy.rest.model.Event; - -import java.util.List; - -// PresenceSyncResponse represents the updates to the presence status of other users during server sync v2. -public class PresenceSyncResponse { - - /** - * List of presence events (array of Event with type m.presence). - */ - public List events; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomInviteState.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomInviteState.java deleted file mode 100644 index 85f3e7ce..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomInviteState.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.sync; - -import im.vector.matrix.android.internal.legacy.rest.model.Event; - -import java.util.List; - -// RoomInviteState represents the state of a room that the user has been invited to. -public class RoomInviteState { - - /** - * List of state events (array of MXEvent). - */ - public List events; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomResponse.java deleted file mode 100644 index 7b39063f..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomResponse.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.sync; - -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.TokensChunkEvents; - -import java.util.List; - -/** - * Class representing a room from a JSON response from room or global initial sync. - */ -public class RoomResponse { - // The room identifier. - public String roomId; - - // The last recent messages of the room. - public TokensChunkEvents messages; - - // The state events. - public List state; - - // The private data that this user has attached to this room. - public List accountData; - - // The current user membership in this room. - public String membership; - - // The room visibility (public/private). - public String visibility; - - // The matrix id of the inviter in case of pending invitation. - public String inviter; - - // The invite event if membership is invite. - public Event invite; - - // The presence status of other users (Provided in case of room initial sync @see http://matrix.org/docs/api/client-server/#!/-rooms/get_room_sync_data)). - public List presence; - - // The read receipts (Provided in case of room initial sync). - public List receipts; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomSync.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomSync.java deleted file mode 100644 index 81595074..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomSync.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.sync; - -import com.google.gson.annotations.SerializedName; - -// RoomSync represents the response for a room during server sync v2. -public class RoomSync { - /** - * The state updates for the room. - */ - public RoomSyncState state; - - /** - * The timeline of messages and state changes in the room. - */ - public RoomSyncTimeline timeline; - - /** - * The ephemeral events in the room that aren't recorded in the timeline or state of the room (e.g. typing, receipts). - */ - public RoomSyncEphemeral ephemeral; - - /** - * The account data events for the room (e.g. tags). - */ - public RoomSyncAccountData accountData; - - /** - The notification counts for the room. - */ - public RoomSyncUnreadNotifications unreadNotifications; - - /** - * The room summary - */ - @SerializedName("summary") - public RoomSyncSummary roomSyncSummary; - -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomSyncAccountData.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomSyncAccountData.java deleted file mode 100644 index fdc2e1c8..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomSyncAccountData.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.sync; - -import im.vector.matrix.android.internal.legacy.rest.model.Event; - -import java.util.List; - -// RoomSyncAccountData represents the account data events for a room. -public class RoomSyncAccountData { - /** - * List of account data events (array of Event). - */ - public List events; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomSyncEphemeral.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomSyncEphemeral.java deleted file mode 100644 index d57b29db..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomSyncEphemeral.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.sync; - -import im.vector.matrix.android.internal.legacy.rest.model.Event; - -import java.util.List; - -// RoomSyncEphemeral represents the ephemeral events in the room that aren't recorded in the timeline or state of the room (e.g. typing). -public class RoomSyncEphemeral { - /** - * List of ephemeral events. - */ - public List events; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomSyncState.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomSyncState.java deleted file mode 100644 index a1d65aa5..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomSyncState.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.sync; - -import im.vector.matrix.android.internal.legacy.rest.model.Event; - -import java.util.List; - -// RoomSyncState represents the state updates for a room during server sync v2. -public class RoomSyncState { - - /** - * List of state events. The resulting state corresponds to the *start* of the timeline. - */ - public List events; - -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomSyncSummary.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomSyncSummary.java deleted file mode 100644 index 399a4dea..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomSyncSummary.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.sync; - -import com.google.gson.annotations.SerializedName; - -import java.util.List; - -/** - * See https://docs.google.com/document/d/11i14UI1cUz-OJ0knD5BFu7fmT6Fo327zvMYqfSAR7xs - */ -public class RoomSyncSummary { - - /** - * Present only if the room has no m.room.name or m.room.canonical_alias. - *

- * Lists the mxids of the first 5 members in the room who are currently joined or invited (ordered by stream ordering as seen on the server, - * to avoid it jumping around if/when topological order changes). As the heroes’ membership status changes, the list changes appropriately - * (sending the whole new list in the next /sync response). This list always excludes the current logged in user. If there are no joined or - * invited users, it lists the parted and banned ones instead. Servers can choose to send more or less than 5 members if they must, but 5 - * seems like a good enough number for most naming purposes. Clients should use all the provided members to name the room, but may truncate - * the list if helpful for UX - */ - @SerializedName("m.heroes") - public List heroes; - - /** - * The number of m.room.members in state 'joined' (including the syncing user) (can be null) - */ - @SerializedName("m.joined_member_count") - public Integer joinedMembersCount; - - /** - * The number of m.room.members in state 'invited' (can be null) - */ - @SerializedName("m.invited_member_count") - public Integer invitedMembersCount; -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomSyncTimeline.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomSyncTimeline.java deleted file mode 100644 index 01c557b2..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomSyncTimeline.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.sync; - -import im.vector.matrix.android.internal.legacy.rest.model.Event; - -import java.util.List; - -/** - * RoomSyncTimeline represents the timeline of messages and state changes for a room during server sync v2. - */ -public class RoomSyncTimeline { - - /** - * List of events. - */ - public List events; - - /** - * Boolean which tells whether there are more events on the server - * In the case of an incremental sync, if the value is true, it's means that there is a gap between known events and received events - */ - public boolean limited; - - /** - * If the batch was limited then this is a token that can be supplied to the server to retrieve more events - */ - public String prevBatch; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomSyncUnreadNotifications.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomSyncUnreadNotifications.java deleted file mode 100644 index 34a869d7..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomSyncUnreadNotifications.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.sync; - -import im.vector.matrix.android.internal.legacy.rest.model.Event; - -import java.util.List; - -/** - `MXRoomSyncUnreadNotifications` represents the unread counts for a room. - */ -public class RoomSyncUnreadNotifications { - /** - * List of account data events (array of Event). - */ - public List events; - - /** - * The number of unread messages that match the push notification rules. - */ - public Integer notificationCount; - - /** - * The number of highlighted unread messages (subset of notifications). - */ - public Integer highlightCount; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomsSyncResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomsSyncResponse.java deleted file mode 100644 index 179e3b2d..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/RoomsSyncResponse.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.sync; - -import java.util.Map; - -// RoomsSyncResponse represents the rooms list in server sync v2 response. -public class RoomsSyncResponse { - - /** - * Joined rooms: keys are rooms ids. - */ - public Map join; - - /** - * Invitations. The rooms that the user has been invited to: keys are rooms ids. - */ - public Map invite; - - /** - * Left rooms. The rooms that the user has left or been banned from: keys are rooms ids. - */ - public Map leave; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/SyncResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/SyncResponse.java deleted file mode 100644 index f13d133b..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/SyncResponse.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.sync; - -import im.vector.matrix.android.internal.legacy.rest.model.group.GroupsSyncResponse; - -import java.util.Map; - -// SyncResponse represents the request response for server sync v2. -public class SyncResponse { - - /** - * The user private data. - */ - public Map accountData; - - /** - * The opaque token for the end. - */ - public String nextBatch; - - /** - * The updates to the presence status of other users. - */ - public PresenceSyncResponse presence; - - /* - * Data directly sent to one of user's devices. - */ - public ToDeviceSyncResponse toDevice; - - /** - * List of rooms. - */ - public RoomsSyncResponse rooms; - - /** - * Devices list update - */ - public DeviceListResponse deviceLists; - - /** - * One time keys management - */ - public DeviceOneTimeKeysCountSyncResponse deviceOneTimeKeysCount; - - /** - * List of groups. - */ - public GroupsSyncResponse groups; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/ToDeviceSyncResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/ToDeviceSyncResponse.java deleted file mode 100644 index 5293459e..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/sync/ToDeviceSyncResponse.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.rest.model.sync; - -import im.vector.matrix.android.internal.legacy.rest.model.Event; - -import java.util.List; - -// ToDeviceSyncResponse represents the data directly sent to one of user's devices. -public class ToDeviceSyncResponse { - - /** - * List of direct-to-device events. - */ - public List events; -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/sync/DefaultEventsThreadListener.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/sync/DefaultEventsThreadListener.java deleted file mode 100644 index 886fb1d3..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/sync/DefaultEventsThreadListener.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.sync; - -import im.vector.matrix.android.internal.legacy.MXDataHandler; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.rest.model.sync.SyncResponse; - -/** - * Listener for the events thread that sends data back to a data handler. - */ -public class DefaultEventsThreadListener implements EventsThreadListener { - - private final MXDataHandler mDataHandler; - - public DefaultEventsThreadListener(MXDataHandler data) { - mDataHandler = data; - } - - @Override - public void onSyncResponse(SyncResponse syncResponse, String fromToken, boolean isCatchingUp) { - mDataHandler.onSyncResponse(syncResponse, fromToken, isCatchingUp); - } - - @Override - public void onSyncError(MatrixError matrixError) { - mDataHandler.onSyncError(matrixError); - } - - @Override - public void onConfigurationError(String matrixErrorCode) { - mDataHandler.onConfigurationError(matrixErrorCode); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/sync/EventsThread.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/sync/EventsThread.java deleted file mode 100644 index dfef023a..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/sync/EventsThread.java +++ /dev/null @@ -1,707 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.sync; - -import android.annotation.SuppressLint; -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.os.Build; -import android.os.Handler; -import android.os.Looper; -import android.os.PowerManager; -import android.os.SystemClock; - -import im.vector.matrix.android.internal.legacy.data.metrics.MetricsListener; -import im.vector.matrix.android.internal.legacy.listeners.IMXNetworkEventListener; -import im.vector.matrix.android.internal.legacy.network.NetworkConnectivityReceiver; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiFailureCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.SimpleApiCallback; -import im.vector.matrix.android.internal.legacy.rest.client.EventsRestClient; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.rest.model.sync.RoomsSyncResponse; -import im.vector.matrix.android.internal.legacy.rest.model.sync.SyncResponse; -import im.vector.matrix.android.internal.legacy.util.Log; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.CountDownLatch; - - -/** - * Thread that continually watches the event stream and sends events to its listener. - */ -public class EventsThread extends Thread { - private static final String LOG_TAG = EventsThread.class.getSimpleName(); - - private static final int RETRY_WAIT_TIME_MS = 10000; - - private static final int DEFAULT_SERVER_TIMEOUT_MS = 30000; - private static final int DEFAULT_CLIENT_TIMEOUT_MS = 120000; - - private EventsRestClient mEventsRestClient; - private EventsThreadListener mListener; - private String mCurrentToken; - - private MetricsListener mMetricsListener; - - private boolean mPaused = true; - private boolean mIsNetworkSuspended = false; - private boolean mIsCatchingUp = false; - private boolean mIsOnline = false; - - private boolean mKilling = false; - - private int mDefaultServerTimeoutms = DEFAULT_SERVER_TIMEOUT_MS; - private int mNextServerTimeoutms = DEFAULT_SERVER_TIMEOUT_MS; - - // add a delay between two sync requests - private final Context mContext; - private int mRequestDelayMs = 0; - private final AlarmManager mAlarmManager; - private PowerManager mPowerManager; - private PendingIntent mPendingDelayedIntent; - private static final Map mSyncObjectByInstance = new HashMap<>(); - - // avoid sync on "this" because it might differ if there is a timer. - private final Object mSyncObject = new Object(); - - // Custom Retrofit error callback that will convert Retrofit errors into our own error callback - private ApiFailureCallback mFailureCallback; - - // avoid restarting the listener if there is no network. - // wait that there is an available network. - private NetworkConnectivityReceiver mNetworkConnectivityReceiver; - private boolean mbIsConnected = true; - - // use dedicated filter when enable - private String mFilterOrFilterId; - - private final IMXNetworkEventListener mNetworkListener = new IMXNetworkEventListener() { - @Override - public void onNetworkConnectionUpdate(boolean isConnected) { - Log.d(LOG_TAG, "onNetworkConnectionUpdate : before " + mbIsConnected + " now " + isConnected); - - synchronized (mSyncObject) { - mbIsConnected = isConnected; - } - - // the thread has been suspended and there is an available network - if (isConnected && !mKilling) { - Log.d(LOG_TAG, "onNetworkConnectionUpdate : call onNetworkAvailable"); - onNetworkAvailable(); - } - } - }; - - /** - * Default constructor. - * - * @param context the context - * @param apiClient API client to make the events API calls - * @param listener a listener to inform - * @param initialToken the sync initial token. - */ - public EventsThread(Context context, EventsRestClient apiClient, EventsThreadListener listener, String initialToken) { - super("Events thread"); - mContext = context; - mEventsRestClient = apiClient; - mListener = listener; - mCurrentToken = initialToken; - mSyncObjectByInstance.put(toString(), this); - mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - } - - /** - * Update the metrics listener mode - * - * @param metricsListener the metrics listener - */ - - public void setMetricsListener(MetricsListener metricsListener) { - this.mMetricsListener = metricsListener; - } - - /** - * @return the current sync token - */ - public String getCurrentSyncToken() { - return mCurrentToken; - } - - /** - * Set filterOrFilterId used for /sync requests - * - * @param filterOrFilterId - */ - public void setFilterOrFilterId(String filterOrFilterId) { - mFilterOrFilterId = filterOrFilterId; - } - - /** - * Update the long poll timeout. - * - * @param ms the timeout in ms - */ - public void setServerLongPollTimeout(int ms) { - mDefaultServerTimeoutms = Math.max(ms, DEFAULT_SERVER_TIMEOUT_MS); - Log.d(LOG_TAG, "setServerLongPollTimeout : " + mDefaultServerTimeoutms); - - } - - /** - * @return the long poll timeout - */ - public int getServerLongPollTimeout() { - return mDefaultServerTimeoutms; - } - - /** - * Set a delay between two sync requests. - * - * @param ms the delay in ms - */ - public void setSyncDelay(int ms) { - mRequestDelayMs = Math.max(0, ms); - - Log.d(LOG_TAG, "## setSyncDelay() : " + mRequestDelayMs + " with state " + getState()); - - if (State.WAITING == getState() && (!mPaused || (0 == mRequestDelayMs) && mIsCatchingUp)) { - if (!mPaused) { - Log.d(LOG_TAG, "## setSyncDelay() : resume the application"); - } - - if ((0 == mRequestDelayMs) && mIsCatchingUp) { - Log.d(LOG_TAG, "## setSyncDelay() : cancel catchup"); - mIsCatchingUp = false; - } - - // and sync asap - synchronized (mSyncObject) { - mSyncObject.notify(); - } - } - } - - /** - * @return the delay between two sync requests. - */ - public int getSyncDelay() { - return mRequestDelayMs; - } - - /** - * Set the network connectivity listener. - * It is used to avoid restarting the events threads each 10 seconds when there is no available network. - * - * @param networkConnectivityReceiver the network receiver - */ - public void setNetworkConnectivityReceiver(NetworkConnectivityReceiver networkConnectivityReceiver) { - mNetworkConnectivityReceiver = networkConnectivityReceiver; - } - - /** - * Set the failure callback. - * - * @param failureCallback the failure callback. - */ - public void setFailureCallback(ApiFailureCallback failureCallback) { - mFailureCallback = failureCallback; - } - - /** - * Pause the thread. It will resume where it left off when pickUp()d. - */ - public void pause() { - Log.d(LOG_TAG, "pause()"); - mPaused = true; - mIsCatchingUp = false; - } - - /** - * A network connection has been retrieved. - */ - private void onNetworkAvailable() { - Log.d(LOG_TAG, "onNetWorkAvailable()"); - if (mIsNetworkSuspended) { - mIsNetworkSuspended = false; - - if (mPaused) { - Log.d(LOG_TAG, "the event thread is still suspended"); - } else { - Log.d(LOG_TAG, "Resume the thread"); - // cancel any catchup process. - mIsCatchingUp = false; - - synchronized (mSyncObject) { - mSyncObject.notify(); - } - } - } else { - Log.d(LOG_TAG, "onNetWorkAvailable() : nothing to do"); - } - } - - /** - * Unpause the thread if it had previously been paused. If not, this does nothing. - */ - public void unpause() { - Log.d(LOG_TAG, "## pickUp() : thread state " + getState()); - - if (State.WAITING == getState()) { - Log.d(LOG_TAG, "## pickUp() : the thread was paused so resume it."); - - mPaused = false; - synchronized (mSyncObject) { - mSyncObject.notify(); - } - } - - // cancel any catchup process. - mIsCatchingUp = false; - } - - /** - * Catchup until some events are retrieved. - */ - public void catchup() { - Log.d(LOG_TAG, "## catchup() : thread state " + getState()); - - if (State.WAITING == getState()) { - Log.d(LOG_TAG, "## catchup() : the thread was paused so wake it up"); - - mPaused = false; - synchronized (mSyncObject) { - mSyncObject.notify(); - } - } - - mIsCatchingUp = true; - } - - /** - * Allow the thread to finish its current processing, then permanently stop. - */ - public void kill() { - Log.d(LOG_TAG, "killing ..."); - - mKilling = true; - - if (mPaused) { - Log.d(LOG_TAG, "killing : the thread was pause so wake it up"); - - mPaused = false; - synchronized (mSyncObject) { - mSyncObject.notify(); - } - - Log.d(LOG_TAG, "Resume the thread to kill it."); - } - } - - /** - * Cancel the killing process - */ - public void cancelKill() { - if (mKilling) { - Log.d(LOG_TAG, "## cancelKill() : Cancel the pending kill"); - mKilling = false; - } else { - Log.d(LOG_TAG, "## cancelKill() : Nothing to d"); - } - } - - /** - * Update the online status - * - * @param isOnline true if the client must be seen as online - */ - public void setIsOnline(boolean isOnline) { - Log.d(LOG_TAG, "setIsOnline to " + isOnline); - mIsOnline = isOnline; - } - - /** - * Tells if the presence is online. - * - * @return true if the user is seen as online. - */ - public boolean isOnline() { - return mIsOnline; - } - - @Override - public void run() { - try { - Looper.prepare(); - } catch (Exception e) { - Log.e(LOG_TAG, "## run() : prepare failed " + e.getMessage(), e); - } - startSync(); - } - - /** - * Tells if a sync request contains some changed devices. - * - * @param syncResponse the sync response - * @return true if the response contains some changed devices. - */ - private static boolean hasDevicesChanged(SyncResponse syncResponse) { - return (null != syncResponse.deviceLists) - && (null != syncResponse.deviceLists.changed) - && (syncResponse.deviceLists.changed.size() > 0); - } - - - /** - * Use a broadcast receiver because the Timer delay might be inaccurate when the screen is turned off. - * For example, request a 1 min delay and get a 6 mins one. - */ - public static class SyncDelayReceiver extends BroadcastReceiver { - public static final String EXTRA_INSTANCE_ID = "EXTRA_INSTANCE_ID"; - - public void onReceive(Context context, Intent intent) { - String instanceId = intent.getStringExtra(EXTRA_INSTANCE_ID); - - if ((null != instanceId) && mSyncObjectByInstance.containsKey(instanceId)) { - EventsThread eventsThread = mSyncObjectByInstance.get(instanceId); - - eventsThread.mPendingDelayedIntent = null; - - Log.d(LOG_TAG, "start a sync after " + eventsThread.mRequestDelayMs + " ms"); - - synchronized (eventsThread.mSyncObject) { - eventsThread.mSyncObject.notify(); - } - } - } - } - - private void resumeInitialSync() { - Log.d(LOG_TAG, "Resuming initial sync from " + mCurrentToken); - // dummy initial sync - // to hide the splash screen - SyncResponse dummySyncResponse = new SyncResponse(); - dummySyncResponse.nextBatch = mCurrentToken; - mListener.onSyncResponse(dummySyncResponse, null, true); - } - - private void executeInitialSync() { - Log.d(LOG_TAG, "Requesting initial sync..."); - long initialSyncStartTime = System.currentTimeMillis(); - while (!isInitialSyncDone()) { - final CountDownLatch latch = new CountDownLatch(1); - mEventsRestClient.syncFromToken(null, 0, DEFAULT_CLIENT_TIMEOUT_MS, mIsOnline ? null : "offline", mFilterOrFilterId, - new SimpleApiCallback(mFailureCallback) { - @Override - public void onSuccess(SyncResponse syncResponse) { - Log.d(LOG_TAG, "Received initial sync response."); - mNextServerTimeoutms = hasDevicesChanged(syncResponse) ? 0 : mDefaultServerTimeoutms; - mListener.onSyncResponse(syncResponse, null, (0 == mNextServerTimeoutms)); - mCurrentToken = syncResponse.nextBatch; - // unblock the events thread - latch.countDown(); - } - - private void sleepAndUnblock() { - Log.i(LOG_TAG, "Waiting a bit before retrying"); - new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { - public void run() { - latch.countDown(); - } - }, RETRY_WAIT_TIME_MS); - } - - @Override - public void onNetworkError(Exception e) { - if (isInitialSyncDone()) { - // Ignore error - // FIXME I think this is the source of infinite initial sync if a network error occurs - // FIXME because latch is not counted down. TO BE TESTED - onSuccess(null); - } else { - Log.e(LOG_TAG, "Sync V2 onNetworkError " + e.getMessage(), e); - super.onNetworkError(e); - sleepAndUnblock(); - } - } - - @Override - public void onMatrixError(MatrixError e) { - super.onMatrixError(e); - - if (MatrixError.isConfigurationErrorCode(e.errcode)) { - mListener.onConfigurationError(e.errcode); - } else { - mListener.onSyncError(e); - sleepAndUnblock(); - } - } - - @Override - public void onUnexpectedError(Exception e) { - super.onUnexpectedError(e); - Log.e(LOG_TAG, "Sync V2 onUnexpectedError " + e.getMessage(), e); - sleepAndUnblock(); - } - }); - - // block until the initial sync callback is invoked. - try { - latch.await(); - } catch (InterruptedException e) { - Log.e(LOG_TAG, "Interrupted whilst performing initial sync.", e); - } catch (Exception e) { - // reported by GA - // The thread might have been killed. - Log.e(LOG_TAG, "latch.await() failed " + e.getMessage(), e); - } - } - long initialSyncEndTime = System.currentTimeMillis(); - long initialSyncDuration = initialSyncEndTime - initialSyncStartTime; - if (mMetricsListener != null) { - mMetricsListener.onInitialSyncFinished(initialSyncDuration); - } - } - - - /** - * Start the events sync - */ - @SuppressLint("NewApi") - private void startSync() { - int serverTimeout; - mPaused = false; - if (isInitialSyncDone()) { - resumeInitialSync(); - serverTimeout = 0; - } else { - // Start with initial sync - executeInitialSync(); - serverTimeout = mNextServerTimeoutms; - } - - Log.d(LOG_TAG, "Starting event stream from token " + mCurrentToken); - // sanity check - if (null != mNetworkConnectivityReceiver) { - mNetworkConnectivityReceiver.addEventListener(mNetworkListener); - // - mbIsConnected = mNetworkConnectivityReceiver.isConnected(); - mIsNetworkSuspended = !mbIsConnected; - } - - // Then repeatedly long-poll for events - - while (!mKilling) { - - // test if a delay between two syncs - if ((!mPaused && !mIsNetworkSuspended) && (0 != mRequestDelayMs)) { - Log.d(LOG_TAG, "startSync : start a delay timer "); - - Intent intent = new Intent(mContext, SyncDelayReceiver.class); - intent.putExtra(SyncDelayReceiver.EXTRA_INSTANCE_ID, toString()); - mPendingDelayedIntent = PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); - - long futureInMillis = SystemClock.elapsedRealtime() + mRequestDelayMs; - - if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) - && mPowerManager.isIgnoringBatteryOptimizations(mContext.getPackageName())) { - mAlarmManager.setAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, futureInMillis, mPendingDelayedIntent); - } else { - mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, futureInMillis, mPendingDelayedIntent); - } - } - - if (mPaused || mIsNetworkSuspended || (null != mPendingDelayedIntent)) { - if (null != mPendingDelayedIntent) { - Log.d(LOG_TAG, "Event stream is paused because there is a timer delay."); - } else if (mIsNetworkSuspended) { - Log.d(LOG_TAG, "Event stream is paused because there is no available network."); - } else { - Log.d(LOG_TAG, "Event stream is paused. Waiting."); - } - - try { - Log.d(LOG_TAG, "startSync : wait ..."); - - synchronized (mSyncObject) { - mSyncObject.wait(); - } - - if (null != mPendingDelayedIntent) { - Log.d(LOG_TAG, "startSync : cancel mSyncDelayTimer"); - mAlarmManager.cancel(mPendingDelayedIntent); - mPendingDelayedIntent.cancel(); - mPendingDelayedIntent = null; - } - - Log.d(LOG_TAG, "Event stream woken from pause."); - - // perform a catchup asap - serverTimeout = 0; - } catch (InterruptedException e) { - Log.e(LOG_TAG, "Unexpected interruption while paused: " + e.getMessage(), e); - } - } - - // the service could have been killed while being paused. - if (!mKilling) { - - long incrementalSyncStartTime = System.currentTimeMillis(); - - final CountDownLatch latch = new CountDownLatch(1); - - Log.d(LOG_TAG, "Get events from token " + mCurrentToken + " with filterOrFilterId " + mFilterOrFilterId); - - final int fServerTimeout = serverTimeout; - mNextServerTimeoutms = mDefaultServerTimeoutms; - - mEventsRestClient.syncFromToken(mCurrentToken, serverTimeout, DEFAULT_CLIENT_TIMEOUT_MS, mIsOnline ? null : "offline", mFilterOrFilterId, - new SimpleApiCallback(mFailureCallback) { - @Override - public void onSuccess(SyncResponse syncResponse) { - if (!mKilling) { - // poll /sync with timeout=0 until - // we get no to_device messages back. - if (0 == fServerTimeout) { - if (hasDevicesChanged(syncResponse)) { - if (mIsCatchingUp) { - Log.d(LOG_TAG, "Some devices have changed but do not set mNextServerTimeoutms to 0 to avoid infinite loops"); - } else { - Log.d(LOG_TAG, "mNextServerTimeoutms is set to 0 because of hasDevicesChanged " - + syncResponse.deviceLists.changed); - mNextServerTimeoutms = 0; - } - } - } - - // the catchup request is suspended when there is no need - // to loop again - if (mIsCatchingUp && (0 != mNextServerTimeoutms)) { - // the catchup triggers sync requests until there are some useful events - int eventCounts = 0; - - if (null != syncResponse.rooms) { - RoomsSyncResponse roomsSyncResponse = syncResponse.rooms; - - if (null != roomsSyncResponse.join) { - eventCounts += roomsSyncResponse.join.size(); - } - - if (null != roomsSyncResponse.invite) { - eventCounts += roomsSyncResponse.invite.size(); - } - } - - // stop any catch up - mIsCatchingUp = false; - mPaused = (0 == mRequestDelayMs); - Log.d(LOG_TAG, "Got " + eventCounts + " useful events while catching up : mPaused is set to " + mPaused); - } - Log.d(LOG_TAG, "Got event response"); - mListener.onSyncResponse(syncResponse, mCurrentToken, (0 == mNextServerTimeoutms)); - mCurrentToken = syncResponse.nextBatch; - Log.d(LOG_TAG, "mCurrentToken is now set to " + mCurrentToken); - - } - - // unblock the events thread - latch.countDown(); - } - - private void onError(String description) { - boolean isConnected; - Log.d(LOG_TAG, "Got an error while polling events " + description); - - synchronized (mSyncObject) { - isConnected = mbIsConnected; - } - - // detected if the device is connected before trying again - if (isConnected) { - new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { - public void run() { - latch.countDown(); - } - }, RETRY_WAIT_TIME_MS); - - } else { - // no network -> wait that a network connection comes back. - mIsNetworkSuspended = true; - latch.countDown(); - } - } - - @Override - public void onNetworkError(Exception e) { - onError(e.getLocalizedMessage()); - } - - @Override - public void onMatrixError(MatrixError e) { - if (MatrixError.isConfigurationErrorCode(e.errcode)) { - mListener.onConfigurationError(e.errcode); - } else { - mListener.onSyncError(e); - onError(e.getLocalizedMessage()); - } - } - - @Override - public void onUnexpectedError(Exception e) { - onError(e.getLocalizedMessage()); - } - }); - - // block until the sync callback is invoked. - try { - latch.await(); - } catch (InterruptedException e) { - Log.e(LOG_TAG, "Interrupted whilst polling message", e); - } catch (Exception e) { - // reported by GA - // The thread might have been killed. - Log.e(LOG_TAG, "latch.await() failed " + e.getMessage(), e); - } - long incrementalSyncEndTime = System.currentTimeMillis(); - long incrementalSyncDuration = incrementalSyncEndTime - incrementalSyncStartTime; - if (mMetricsListener != null) { - mMetricsListener.onIncrementalSyncFinished(incrementalSyncDuration); - } - } - serverTimeout = mNextServerTimeoutms; - } - - if (null != mNetworkConnectivityReceiver) { - mNetworkConnectivityReceiver.removeEventListener(mNetworkListener); - } - Log.d(LOG_TAG, "Event stream terminating."); - } - - /** - * Ask if the initial sync is done. It means we have a sync token - * - * @return - */ - private boolean isInitialSyncDone() { - return mCurrentToken != null; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/sync/EventsThreadListener.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/sync/EventsThreadListener.java deleted file mode 100644 index d858a7fb..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/sync/EventsThreadListener.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.sync; - -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.rest.model.sync.SyncResponse; - -/** - * Interface to implement to listen to the event thread. - */ -public interface EventsThreadListener { - /** - * Call when a sync request has been performed with the API V2. - * - * @param response the response (can be null) - * @param fromToken the start token - * @param isCatchingUp true if a catchup is on progress - */ - void onSyncResponse(SyncResponse response, String fromToken, boolean isCatchingUp); - - /** - * The sync has encountered an error - * - * @param matrixError the matrix error - */ - void onSyncError(final MatrixError matrixError); - - /** - * A configuration error has been received. - * - * @param matrixErrorCode the matrix error code - */ - void onConfigurationError(String matrixErrorCode); -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/BingRulesManager.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/BingRulesManager.java deleted file mode 100644 index 86ab5717..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/BingRulesManager.java +++ /dev/null @@ -1,1106 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.util; - -import android.text.TextUtils; - -import im.vector.matrix.android.internal.legacy.MXDataHandler; -import im.vector.matrix.android.internal.legacy.MXSession; -import im.vector.matrix.android.internal.legacy.data.MyUser; -import im.vector.matrix.android.internal.legacy.data.Room; -import im.vector.matrix.android.internal.legacy.listeners.IMXNetworkEventListener; -import im.vector.matrix.android.internal.legacy.network.NetworkConnectivityReceiver; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.SimpleApiCallback; -import im.vector.matrix.android.internal.legacy.rest.client.PushRulesRestClient; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.BingRule; -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.Condition; -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.ContainsDisplayNameCondition; -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.ContentRule; -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.EventMatchCondition; -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.PushRuleSet; -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.PushRulesResponse; -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.RoomMemberCountCondition; -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.SenderNotificationPermissionCondition; -import im.vector.matrix.android.internal.legacy.rest.model.message.Message; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.regex.Pattern; - -/** - * Object that gets and processes bing rules from the server. - */ -public class BingRulesManager { - private static final String LOG_TAG = BingRulesManager.class.getSimpleName(); - - /** - * Bing rule listener - */ - public interface onBingRuleUpdateListener { - /** - * The manager succeeds to update the bingrule enable status. - */ - void onBingRuleUpdateSuccess(); - - /** - * The manager fails to update the bingrule enable status. - * - * @param errorMessage the error message. - */ - void onBingRuleUpdateFailure(String errorMessage); - } - - /** - * Bing rules update - */ - public interface onBingRulesUpdateListener { - /** - * Warn that some bing rules have been updated - */ - void onBingRulesUpdate(); - } - - // general members - private final PushRulesRestClient mApiClient; - private final MXSession mSession; - private final String mMyUserId; - private final MXDataHandler mDataHandler; - - // the rules set to apply - private PushRuleSet mRulesSet = new PushRuleSet(); - - // the rules list - private final List mRules = new ArrayList<>(); - - // the default bing rule - private BingRule mDefaultBingRule = new BingRule(true); - - // tell if the bing rules set is initialized - private boolean mIsInitialized = false; - - // map to check if a room is "mention only" - private final Map mIsMentionOnlyMap = new HashMap<>(); - - // network management - private NetworkConnectivityReceiver mNetworkConnectivityReceiver; - private IMXNetworkEventListener mNetworkListener; - private ApiCallback mLoadRulesCallback; - - // listener - private final Set mBingRulesUpdateListeners = new HashSet<>(); - - /** - * Defines the room notification state - */ - public enum RoomNotificationState { - /** - * All the messages will trigger a noisy notification - */ - ALL_MESSAGES_NOISY, - - /** - * All the messages will trigger a notification - */ - ALL_MESSAGES, - - /** - * Only the messages with user display name / user name will trigger notifications - */ - MENTIONS_ONLY, - - /** - * No notifications - */ - MUTE - } - - private Map mRoomNotificationStateByRoomId = new HashMap<>(); - - /** - * Constructor - * - * @param session the session - * @param networkConnectivityReceiver the network events listener - */ - public BingRulesManager(MXSession session, NetworkConnectivityReceiver networkConnectivityReceiver) { - mSession = session; - mApiClient = session.getBingRulesApiClient(); - mMyUserId = session.getCredentials().getUserId(); - mDataHandler = session.getDataHandler(); - - mNetworkListener = new IMXNetworkEventListener() { - @Override - public void onNetworkConnectionUpdate(boolean isConnected) { - // mLoadRulesCallback is set when a loadRules failed - // so when a network is available, trigger again loadRules - if (isConnected && (null != mLoadRulesCallback)) { - loadRules(mLoadRulesCallback); - } - } - }; - - mNetworkConnectivityReceiver = networkConnectivityReceiver; - networkConnectivityReceiver.addEventListener(mNetworkListener); - } - - /** - * @return true if it is ready to be used (i.e initializedà - */ - public boolean isReady() { - return mIsInitialized; - } - - /** - * Remove the network events listener. - * This listener is only used to initialize the rules at application launch. - */ - private void removeNetworkListener() { - if ((null != mNetworkConnectivityReceiver) && (null != mNetworkListener)) { - mNetworkConnectivityReceiver.removeEventListener(mNetworkListener); - mNetworkConnectivityReceiver = null; - mNetworkListener = null; - } - } - - /** - * Add a listener - * - * @param listener the listener - */ - public void addBingRulesUpdateListener(onBingRulesUpdateListener listener) { - if (null != listener) { - mBingRulesUpdateListeners.add(listener); - } - } - - /** - * remove a listener - * - * @param listener the listener - */ - public void removeBingRulesUpdateListener(onBingRulesUpdateListener listener) { - if (null != listener) { - mBingRulesUpdateListeners.remove(listener); - } - } - - /** - * Some rules have been updated. - */ - private void onBingRulesUpdate() { - // delete cached data - mRoomNotificationStateByRoomId.clear(); - - for (onBingRulesUpdateListener listener : mBingRulesUpdateListeners) { - try { - listener.onBingRulesUpdate(); - } catch (Exception e) { - Log.e(LOG_TAG, "## onBingRulesUpdate() : onBingRulesUpdate failed " + e.getMessage(), e); - } - } - } - - /** - * Load the bing rules from the server. - * - * @param callback an async callback called when the rules are loaded - */ - public void loadRules(final ApiCallback callback) { - mLoadRulesCallback = null; - - Log.d(LOG_TAG, "## loadRules() : refresh the bing rules"); - mApiClient.getAllRules(new ApiCallback() { - @Override - public void onSuccess(PushRulesResponse info) { - Log.d(LOG_TAG, "## loadRules() : succeeds"); - - buildRules(info); - mIsInitialized = true; - - if (callback != null) { - callback.onSuccess(null); - } - - removeNetworkListener(); - } - - private void onError(String errorMessage) { - Log.e(LOG_TAG, "## loadRules() : failed " + errorMessage); - // the callback will be called when the request will succeed - mLoadRulesCallback = callback; - } - - @Override - public void onNetworkError(Exception e) { - onError(e.getMessage()); - - if (null != callback) { - callback.onNetworkError(e); - } - } - - @Override - public void onMatrixError(MatrixError e) { - onError(e.getMessage()); - - if (null != callback) { - callback.onMatrixError(e); - } - } - - @Override - public void onUnexpectedError(Exception e) { - onError(e.getMessage()); - - if (null != callback) { - callback.onUnexpectedError(e); - } - } - }); - } - - /** - * Returns whether a string contains an occurrence of another, as a standalone word, regardless of case. - * - * @param subString the string to search for - * @param longString the string to search in - * @return whether a match was found - */ - private static boolean caseInsensitiveFind(String subString, String longString) { - // sanity check - if (TextUtils.isEmpty(subString) || TextUtils.isEmpty(longString)) { - return false; - } - - boolean found = false; - - try { - Pattern pattern = Pattern.compile("(\\W|^)" + subString + "(\\W|$)", Pattern.CASE_INSENSITIVE); - found = pattern.matcher(longString).find(); - } catch (Exception e) { - Log.e(LOG_TAG, "caseInsensitiveFind : pattern.matcher failed with " + e.getMessage(), e); - } - - return found; - } - - /** - * Returns the first highlighted notifiable bing rule which fulfills its condition with this event. - * - * @param event the event - * @return the first matched bing rule, null if none - */ - public BingRule fulfilledHighlightBingRule(Event event) { - return fulfilledBingRule(event, true); - } - - /** - * Returns the first notifiable bing rule which fulfills its condition with this event. - * - * @param event the event - * @return the first matched bing rule, null if none - */ - public BingRule fulfilledBingRule(Event event) { - return fulfilledBingRule(event, false); - } - - /** - * Returns the first notifiable bing rule which fulfills its condition with this event. - * - * @param event the event - * @param highlightRuleOnly true to only check the highlight rule - * @return the first matched bing rule, null if none - */ - private BingRule fulfilledBingRule(Event event, boolean highlightRuleOnly) { - // sanity check - if (null == event) { - Log.e(LOG_TAG, "## fulfilledBingRule() : null event"); - return null; - } - - if (!mIsInitialized) { - Log.e(LOG_TAG, "## fulfilledBingRule() : not initialized"); - return null; - } - - if (0 == mRules.size()) { - Log.e(LOG_TAG, "## fulfilledBingRule() : no rules"); - return null; - } - - // do not trigger notification for oneself messages - if ((null != event.getSender()) && TextUtils.equals(event.getSender(), mMyUserId)) { - return null; - } - - String eventType = event.getType(); - - // some types are not bingable - if (TextUtils.equals(eventType, Event.EVENT_TYPE_PRESENCE) - || TextUtils.equals(eventType, Event.EVENT_TYPE_TYPING) - || TextUtils.equals(eventType, Event.EVENT_TYPE_REDACTION) - || TextUtils.equals(eventType, Event.EVENT_TYPE_RECEIPT) - || TextUtils.equals(eventType, Event.EVENT_TYPE_TAGS)) { - return null; - } - - // GA issue - final List rules; - - synchronized (this) { - rules = new ArrayList<>(mRules); - } - - // Go down the rule list until we find a match - for (BingRule bingRule : rules) { - if (bingRule.isEnabled && (!highlightRuleOnly || bingRule.shouldHighlight())) { - boolean isFullfilled = false; - - // some rules have no condition - // so their ruleId defines the method - if (BingRule.RULE_ID_CONTAIN_USER_NAME.equals(bingRule.ruleId) || BingRule.RULE_ID_CONTAIN_DISPLAY_NAME.equals(bingRule.ruleId)) { - if (Event.EVENT_TYPE_MESSAGE.equals(event.getType())) { - Message message = JsonUtils.toMessage(event.getContent()); - MyUser myUser = mSession.getMyUser(); - String pattern = null; - - if (BingRule.RULE_ID_CONTAIN_USER_NAME.equals(bingRule.ruleId)) { - if (mMyUserId.indexOf(":") >= 0) { - pattern = mMyUserId.substring(1, mMyUserId.indexOf(":")); - } else { - pattern = mMyUserId; - } - } else if (BingRule.RULE_ID_CONTAIN_DISPLAY_NAME.equals(bingRule.ruleId)) { - pattern = myUser.displayname; - if ((null != mSession.getDataHandler()) && (null != mSession.getDataHandler().getStore())) { - Room room = mSession.getDataHandler().getStore().getRoom(event.roomId); - - if ((null != room) && (null != room.getState())) { - String disambiguousedName = room.getState().getMemberName(mMyUserId); - - if (!TextUtils.equals(disambiguousedName, mMyUserId)) { - pattern = Pattern.quote(disambiguousedName); - } - } - } - } - - if (!TextUtils.isEmpty(pattern)) { - isFullfilled = caseInsensitiveFind(pattern, message.body); - } - } - } else if (BingRule.RULE_ID_FALLBACK.equals(bingRule.ruleId)) { - isFullfilled = true; - } else { - // some default rules define conditions - // so use them instead of doing a custom treatment - // RULE_ID_ONE_TO_ONE_ROOM - // RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS - isFullfilled = eventMatchesConditions(event, bingRule.conditions); - } - - if (isFullfilled) { - return bingRule; - } - } - } - - // no rules are fulfilled - return null; - } - - /** - * Check if an event matches a conditions set - * - * @param event the event to test - * @param conditions the conditions set - * @return true if the event matches all the conditions set. - */ - private boolean eventMatchesConditions(Event event, List conditions) { - try { - if ((conditions != null) && (event != null)) { - for (Condition condition : conditions) { - if (condition instanceof EventMatchCondition) { - if (!((EventMatchCondition) condition).isSatisfied(event)) { - return false; - } - } else if (condition instanceof ContainsDisplayNameCondition) { - String myDisplayName = null; - - if (event.roomId != null) { - Room room = mDataHandler.getRoom(event.roomId, false); - - // sanity checks - if (room != null && room.getMember(mMyUserId) != null) { - // Best way to get your display name for now - myDisplayName = room.getMember(mMyUserId).displayname; - } - } - - if (TextUtils.isEmpty(myDisplayName)) { - // RoomMember is maybe not known due to lazy loading - // Get displayName from the session - myDisplayName = mSession.getMyUser().displayname; - } - - if (!((ContainsDisplayNameCondition) condition).isSatisfied(event, myDisplayName)) { - return false; - } - } else if (condition instanceof RoomMemberCountCondition) { - if (event.roomId != null) { - Room room = mDataHandler.getRoom(event.roomId, false); - - if (!((RoomMemberCountCondition) condition).isSatisfied(room)) { - return false; - } - } - } else if (condition instanceof SenderNotificationPermissionCondition) { - if (event.roomId != null) { - Room room = mDataHandler.getRoom(event.roomId, false); - - if (!((SenderNotificationPermissionCondition) condition).isSatisfied(room.getState().getPowerLevels(), event.sender)) { - return false; - } - } - } else { - // unknown conditions: we previously matched all unknown conditions, - // but given that rules can be added to the base rules on a server, - // it's probably better to not match unknown conditions. - return false; - } - } - } - } catch (Exception e) { - Log.e(LOG_TAG, "## eventMatchesConditions() failed " + e.getMessage(), e); - return false; - } - return true; - } - - /** - * Build the internal push rules - * - * @param pushRulesResponse the server request response. - */ - public void buildRules(PushRulesResponse pushRulesResponse) { - if (null != pushRulesResponse) { - updateRulesSet(pushRulesResponse.global); - onBingRulesUpdate(); - } - } - - /** - * @return the rules set - */ - public PushRuleSet pushRules() { - return mRulesSet; - } - - /** - * Update mRulesSet with the new one. - * - * @param ruleSet the new ruleSet to apply - */ - private void updateRulesSet(PushRuleSet ruleSet) { - synchronized (this) { - // clear the rules list - // it is - mRules.clear(); - - // sanity check - if (null == ruleSet) { - mRulesSet = new PushRuleSet(); - return; - } - - // Replace the list by ArrayList to be able to add/remove rules - // Add the rule kind in each rule - // Ensure that the null pointers are replaced by an empty list - if (ruleSet.override != null) { - ruleSet.override = new ArrayList<>(ruleSet.override); - for (BingRule rule : ruleSet.override) { - rule.kind = BingRule.KIND_OVERRIDE; - } - mRules.addAll(ruleSet.override); - } else { - ruleSet.override = new ArrayList<>(ruleSet.override); - } - - if (ruleSet.content != null) { - ruleSet.content = new ArrayList<>(ruleSet.content); - for (BingRule rule : ruleSet.content) { - rule.kind = BingRule.KIND_CONTENT; - } - addContentRules(ruleSet.content); - } else { - ruleSet.content = new ArrayList<>(); - } - - mIsMentionOnlyMap.clear(); - if (ruleSet.room != null) { - ruleSet.room = new ArrayList<>(ruleSet.room); - - for (BingRule rule : ruleSet.room) { - rule.kind = BingRule.KIND_ROOM; - } - addRoomRules(ruleSet.room); - } else { - ruleSet.room = new ArrayList<>(); - } - - if (ruleSet.sender != null) { - ruleSet.sender = new ArrayList<>(ruleSet.sender); - - for (BingRule rule : ruleSet.sender) { - rule.kind = BingRule.KIND_SENDER; - } - addSenderRules(ruleSet.sender); - } else { - ruleSet.sender = new ArrayList<>(); - } - - if (ruleSet.underride != null) { - ruleSet.underride = new ArrayList<>(ruleSet.underride); - for (BingRule rule : ruleSet.underride) { - rule.kind = BingRule.KIND_UNDERRIDE; - } - mRules.addAll(ruleSet.underride); - } else { - ruleSet.underride = new ArrayList<>(); - } - - mRulesSet = ruleSet; - - Log.d(LOG_TAG, "## updateRules() : has " + mRules.size() + " rules"); - } - } - - /** - * Create a content EventMatchConditions list from a ContentRules list - * - * @param rules the ContentRules list - */ - private void addContentRules(List rules) { - // sanity check - if (null != rules) { - for (ContentRule rule : rules) { - EventMatchCondition condition = new EventMatchCondition(); - condition.kind = Condition.KIND_EVENT_MATCH; - condition.key = "content.body"; - condition.pattern = rule.pattern; - - rule.addCondition(condition); - - mRules.add(rule); - } - } - } - - /** - * Create a room EventMatchConditions list from a BingRule list - * - * @param rules the BingRule list - */ - private void addRoomRules(List rules) { - if (null != rules) { - for (BingRule rule : rules) { - EventMatchCondition condition = new EventMatchCondition(); - condition.kind = Condition.KIND_EVENT_MATCH; - condition.key = "room_id"; - condition.pattern = rule.ruleId; - - rule.addCondition(condition); - - mRules.add(rule); - } - } - } - - /** - * Create a sender EventMatchConditions list from a BingRule list - * - * @param rules the BingRule list - */ - private void addSenderRules(List rules) { - if (null != rules) { - for (BingRule rule : rules) { - EventMatchCondition condition = new EventMatchCondition(); - condition.kind = Condition.KIND_EVENT_MATCH; - condition.key = "user_id"; - condition.pattern = rule.ruleId; - - rule.addCondition(condition); - - mRules.add(rule); - } - } - } - - /** - * Force to refresh the rules. - * The listener is called when the rules are refreshed. - * - * @param errorMsg the error message to dispatch. - * @param listener the asynchronous listener - */ - private void forceRulesRefresh(final String errorMsg, final onBingRuleUpdateListener listener) { - // refresh only there is a listener - if (null != listener) { - // clear cached data - mRoomNotificationStateByRoomId.clear(); - - loadRules(new ApiCallback() { - private void onDone(String error) { - // clear cached data - mRoomNotificationStateByRoomId.clear(); - - try { - if (TextUtils.isEmpty(error) && TextUtils.isEmpty(errorMsg)) { - listener.onBingRuleUpdateSuccess(); - } else { - listener.onBingRuleUpdateFailure(TextUtils.isEmpty(errorMsg) ? error : errorMsg); - } - } catch (Exception e) { - Log.e(LOG_TAG, "## forceRulesRefresh() : failed " + e.getMessage(), e); - } - } - - @Override - public void onSuccess(Void info) { - onDone(null); - } - - @Override - public void onNetworkError(Exception e) { - onDone(e.getLocalizedMessage()); - } - - @Override - public void onMatrixError(MatrixError e) { - onDone(e.getLocalizedMessage()); - } - - @Override - public void onUnexpectedError(Exception e) { - onDone(e.getLocalizedMessage()); - } - }); - } - } - - /** - * Get the rules update callback. - * - * @param listener the listener - * @return the asynchronous callback - */ - private ApiCallback getUpdateCallback(final onBingRuleUpdateListener listener) { - return new ApiCallback() { - @Override - public void onSuccess(Void info) { - forceRulesRefresh(null, listener); - } - - private void onError(String message) { - forceRulesRefresh(message, listener); - } - - /** - * Called if there is a network error. - * - * @param e the exception - */ - @Override - public void onNetworkError(Exception e) { - onError(e.getLocalizedMessage()); - } - - /** - * Called in case of a Matrix error. - * - * @param e the Matrix error - */ - @Override - public void onMatrixError(MatrixError e) { - onError(e.getLocalizedMessage()); - } - - /** - * Called for some other type of error. - * - * @param e the exception - */ - @Override - public void onUnexpectedError(Exception e) { - onError(e.getLocalizedMessage()); - } - }; - } - - /** - * Update the rule enable status. - * The rules lits are refreshed when the listener is called. - * - * @param rule the bing rule to toggle. - * @param listener the rule update listener. - */ - public void updateEnableRuleStatus(final BingRule rule, final boolean isEnabled, final onBingRuleUpdateListener listener) { - if (null != rule) { - mApiClient.updateEnableRuleStatus(rule.kind, rule.ruleId, isEnabled, getUpdateCallback(listener)); - } - } - - /** - * Delete the rule. - * The rules lists are refreshed when the listener is called. - * - * @param rule the rule to delete. - * @param listener the rule update listener. - */ - public void deleteRule(final BingRule rule, final onBingRuleUpdateListener listener) { - // null case - if (null == rule) { - if (listener != null) { - try { - listener.onBingRuleUpdateSuccess(); - } catch (Exception e) { - Log.e(LOG_TAG, "## deleteRule : onBingRuleUpdateSuccess failed " + e.getMessage(), e); - } - } - return; - } - - mApiClient.deleteRule(rule.kind, rule.ruleId, getUpdateCallback(listener)); - } - - /** - * Delete a rules list. - * The rules lists are refreshed when the listener is called. - * - * @param rules the rules to delete - * @param listener the listener when the rules are deleted - */ - public void deleteRules(final List rules, final onBingRuleUpdateListener listener) { - deleteRules(rules, 0, listener); - } - - /** - * Recursive rules deletion method. - * - * @param rules the rules to delete - * @param index the rule index - * @param listener the listener when the rules are deleted - */ - private void deleteRules(final List rules, final int index, final onBingRuleUpdateListener listener) { - // sanity checks - if ((null == rules) || (index >= rules.size())) { - onBingRulesUpdate(); - if (null != listener) { - try { - listener.onBingRuleUpdateSuccess(); - } catch (Exception e) { - Log.e(LOG_TAG, "## deleteRules() : onBingRuleUpdateSuccess failed " + e.getMessage(), e); - } - } - - return; - } - - // delete the rule - deleteRule(rules.get(index), new onBingRuleUpdateListener() { - @Override - public void onBingRuleUpdateSuccess() { - deleteRules(rules, index + 1, listener); - } - - @Override - public void onBingRuleUpdateFailure(String errorMessage) { - if (null != listener) { - try { - listener.onBingRuleUpdateFailure(errorMessage); - } catch (Exception e) { - Log.e(LOG_TAG, "## deleteRules() : onBingRuleUpdateFailure failed " + e.getMessage(), e); - } - } - } - }); - } - - /** - * Add a rule. - * The rules lists are refreshed when the listener is called. - * - * @param rule the rule to delete. - * @param listener the rule update listener. - */ - public void addRule(final BingRule rule, final onBingRuleUpdateListener listener) { - // null case - if (null == rule) { - if (listener != null) { - try { - listener.onBingRuleUpdateSuccess(); - } catch (Exception e) { - Log.e(LOG_TAG, "## addRule : onBingRuleUpdateSuccess failed " + e.getMessage(), e); - } - } - return; - } - - mApiClient.addRule(rule, getUpdateCallback(listener)); - } - - /** - * Update a bing rule. - * The rules list are updated when the callback is called. - * - * @param source the source - * @param target the target - * @param listener the listener - */ - public void updateRule(final BingRule source, final BingRule target, final onBingRuleUpdateListener listener) { - if (null == source) { - addRule(target, listener); - return; - } - - if (null == target) { - deleteRule(source, listener); - return; - } - - if (source.isEnabled != target.isEnabled) { - mApiClient.updateEnableRuleStatus(target.kind, target.ruleId, target.isEnabled, new ApiCallback() { - @Override - public void onSuccess(Void info) { - source.isEnabled = target.isEnabled; - updateRule(source, target, listener); - } - - @Override - public void onNetworkError(Exception e) { - forceRulesRefresh(e.getLocalizedMessage(), listener); - } - - @Override - public void onMatrixError(MatrixError e) { - forceRulesRefresh(e.getLocalizedMessage(), listener); - } - - @Override - public void onUnexpectedError(Exception e) { - forceRulesRefresh(e.getLocalizedMessage(), listener); - } - }); - - return; - } - - if (source.actions != target.actions) { - Map map = new HashMap<>(); - List sortedActions = new ArrayList<>(); - - // the webclient needs to have them sorted - if (null != target.actions) { - if (target.actions.contains(BingRule.ACTION_NOTIFY)) { - sortedActions.add(BingRule.ACTION_NOTIFY); - } - - if (target.actions.contains(BingRule.ACTION_DONT_NOTIFY)) { - sortedActions.add(BingRule.ACTION_DONT_NOTIFY); - } - - if (null != target.getActionMap(BingRule.ACTION_SET_TWEAK_SOUND_VALUE)) { - sortedActions.add(target.getActionMap(BingRule.ACTION_SET_TWEAK_SOUND_VALUE)); - } - - if (null != target.getActionMap(BingRule.ACTION_SET_TWEAK_HIGHLIGHT_VALUE)) { - sortedActions.add(target.getActionMap(BingRule.ACTION_SET_TWEAK_HIGHLIGHT_VALUE)); - } - } - - map.put("actions", sortedActions); - - mApiClient.updateRuleActions(target.kind, target.ruleId, map, new SimpleApiCallback() { - @Override - public void onSuccess(Void info) { - source.actions = target.actions; - updateRule(source, target, listener); - } - - @Override - public void onNetworkError(Exception e) { - forceRulesRefresh(e.getLocalizedMessage(), listener); - } - - @Override - public void onMatrixError(MatrixError e) { - forceRulesRefresh(e.getLocalizedMessage(), listener); - } - - @Override - public void onUnexpectedError(Exception e) { - forceRulesRefresh(e.getLocalizedMessage(), listener); - } - }); - - return; - } - - // the update succeeds - forceRulesRefresh(null, listener); - } - - /** - * Search the push rules for the room id - * - * @param roomId the room id - * @return the room rules list - */ - private List getPushRulesForRoomId(String roomId) { - List rules = new ArrayList<>(); - - // sanity checks - if (!TextUtils.isEmpty(roomId) && (null != mRulesSet)) { - // the webclient defines two ways to set a room rule - // mention only : the user won't have any push for the room except if a content rule is fulfilled - // mute : no notification for this room - - // mute rules are defined in override groups - if (null != mRulesSet.override) { - for (BingRule roomRule : mRulesSet.override) { - if (TextUtils.equals(roomRule.ruleId, roomId)) { - rules.add(roomRule); - } - } - } - - // mention only are defined in room group - if (null != mRulesSet.room) { - for (BingRule roomRule : mRulesSet.room) { - if (TextUtils.equals(roomRule.ruleId, roomId)) { - rules.add(roomRule); - } - } - } - } - - return rules; - } - - /** - * Provide the room notification state - * - * @param roomId the room - * @return the room notification state - */ - public RoomNotificationState getRoomNotificationState(String roomId) { - if (TextUtils.isEmpty(roomId)) { - return RoomNotificationState.ALL_MESSAGES; - } - - if (mRoomNotificationStateByRoomId.containsKey(roomId)) { - return mRoomNotificationStateByRoomId.get(roomId); - } - - RoomNotificationState result = RoomNotificationState.ALL_MESSAGES; - List bingRules = getPushRulesForRoomId(roomId); - - for (BingRule rule : bingRules) { - if (rule.isEnabled) { - if (rule.shouldNotNotify()) { - result = TextUtils.equals(rule.kind, BingRule.KIND_OVERRIDE) ? RoomNotificationState.MUTE : RoomNotificationState.MENTIONS_ONLY; - break; - } else if (rule.shouldNotify()) { - result = (null != rule.getNotificationSound()) ? RoomNotificationState.ALL_MESSAGES_NOISY : RoomNotificationState.ALL_MESSAGES; - } - } - } - - mRoomNotificationStateByRoomId.put(roomId, result); - return result; - } - - /** - * Update the notification state of a dedicated room - * - * @param roomId the room id - * @param state the new state - * @param listener the asynchronous callback - */ - public void updateRoomNotificationState(final String roomId, final RoomNotificationState state, final onBingRuleUpdateListener listener) { - List bingRules = getPushRulesForRoomId(roomId); - - deleteRules(bingRules, new onBingRuleUpdateListener() { - @Override - public void onBingRuleUpdateSuccess() { - if (state == RoomNotificationState.ALL_MESSAGES) { - forceRulesRefresh(null, listener); - } else { - BingRule rule; - - if (state == RoomNotificationState.ALL_MESSAGES_NOISY) { - rule = new BingRule(BingRule.KIND_ROOM, roomId, true, false, true); - } else { - rule = new BingRule((state == RoomNotificationState.MENTIONS_ONLY) ? - BingRule.KIND_ROOM : BingRule.KIND_OVERRIDE, roomId, false, null, false); - - EventMatchCondition condition = new EventMatchCondition(); - condition.key = "room_id"; - condition.pattern = roomId; - rule.addCondition(condition); - - } - - addRule(rule, listener); - } - } - - @Override - public void onBingRuleUpdateFailure(String errorMessage) { - listener.onBingRuleUpdateFailure(errorMessage); - } - }); - } - - /** - * Tell whether the regular notifications are disabled for the room. - * - * @param roomId the room id - * @return true if the regular notifications are disabled (mention only) - */ - public boolean isRoomMentionOnly(String roomId) { - return RoomNotificationState.MENTIONS_ONLY == getRoomNotificationState(roomId); - } - - /** - * Test if the room has a dedicated rule which disables notification. - * - * @param roomId the roomId - * @return true if there is a rule to disable notifications. - */ - public boolean isRoomNotificationsDisabled(String roomId) { - RoomNotificationState state = getRoomNotificationState(roomId); - return (RoomNotificationState.MENTIONS_ONLY == state) || (RoomNotificationState.MUTE == state); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/CompatUtil.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/CompatUtil.java deleted file mode 100644 index fb52caff..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/CompatUtil.java +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.util; - -import android.content.Context; -import android.content.SharedPreferences; -import android.os.Build; -import android.preference.PreferenceManager; -import android.security.KeyPairGeneratorSpec; -import android.security.keystore.KeyGenParameterSpec; -import android.security.keystore.KeyProperties; -import android.support.annotation.Nullable; -import android.support.annotation.RequiresApi; -import android.util.Base64; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.math.BigInteger; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.PrivateKey; -import java.security.SecureRandom; -import java.security.UnrecoverableKeyException; -import java.security.cert.CertificateException; -import java.security.spec.AlgorithmParameterSpec; -import java.security.spec.RSAKeyGenParameterSpec; -import java.util.Calendar; -import java.util.zip.GZIPOutputStream; - -import javax.crypto.Cipher; -import javax.crypto.CipherInputStream; -import javax.crypto.CipherOutputStream; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.KeyGenerator; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.SecretKey; -import javax.crypto.spec.GCMParameterSpec; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; -import javax.security.auth.x500.X500Principal; - -public class CompatUtil { - private static final String TAG = CompatUtil.class.getSimpleName(); - private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore"; - private static final String AES_GCM_CIPHER_TYPE = "AES/GCM/NoPadding"; - private static final int AES_GCM_KEY_SIZE_IN_BITS = 128; - private static final int AES_GCM_IV_LENGTH = 12; - private static final String AES_LOCAL_PROTECTION_KEY_ALIAS = "aes_local_protection"; - - private static final String RSA_WRAP_LOCAL_PROTECTION_KEY_ALIAS = "rsa_wrap_local_protection"; - private static final String RSA_WRAP_CIPHER_TYPE = "RSA/NONE/PKCS1Padding"; - private static final String AES_WRAPPED_PROTECTION_KEY_SHARED_PREFERENCE = "aes_wrapped_local_protection"; - - private static final String SHARED_KEY_ANDROID_VERSION_WHEN_KEY_HAS_BEEN_GENERATED = "android_version_when_key_has_been_generated"; - - private static SecretKeyAndVersion sSecretKeyAndVersion; - private static SecureRandom sPrng; - - /** - * Create a GZIPOutputStream instance - * Special treatment on KitKat device, force the syncFlush param to false - * Before Kitkat, this param does not exist and after Kitkat it is set to false by default - * - * @param outputStream the output stream - */ - public static GZIPOutputStream createGzipOutputStream(OutputStream outputStream) throws IOException { - if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) { - return new GZIPOutputStream(outputStream, false); - } else { - return new GZIPOutputStream(outputStream); - } - } - - /** - * Returns the AES key used for local storage encryption/decryption with AES/GCM. - * The key is created if it does not exist already in the keystore. - * From Marshmallow, this key is generated and operated directly from the android keystore. - * From KitKat and before Marshmallow, this key is stored in the application shared preferences - * wrapped by a RSA key generated and operated directly from the android keystore. - * - * @param context the context holding the application shared preferences - */ - @RequiresApi(Build.VERSION_CODES.KITKAT) - private static synchronized SecretKeyAndVersion getAesGcmLocalProtectionKey(Context context) - throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException, - NoSuchProviderException, InvalidAlgorithmParameterException, NoSuchPaddingException, - InvalidKeyException, IllegalBlockSizeException, UnrecoverableKeyException { - if (sSecretKeyAndVersion == null) { - final KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER); - keyStore.load(null); - - Log.i(TAG, "Loading local protection key"); - - SecretKey key; - - final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); - // Get the version of Android when the key has been generated, default to the current version of the system. In this case, the - // key will be generated - final int androidVersionWhenTheKeyHasBeenGenerated - = sharedPreferences.getInt(SHARED_KEY_ANDROID_VERSION_WHEN_KEY_HAS_BEEN_GENERATED, Build.VERSION.SDK_INT); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - if (keyStore.containsAlias(AES_LOCAL_PROTECTION_KEY_ALIAS)) { - Log.i(TAG, "AES local protection key found in keystore"); - key = (SecretKey) keyStore.getKey(AES_LOCAL_PROTECTION_KEY_ALIAS, null); - } else { - // Check if a key has been created on version < M (in case of OS upgrade) - key = readKeyApiL(sharedPreferences, keyStore); - - if (key == null) { - Log.i(TAG, "Generating AES key with keystore"); - final KeyGenerator generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE_PROVIDER); - generator.init( - new KeyGenParameterSpec.Builder(AES_LOCAL_PROTECTION_KEY_ALIAS, - KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) - .setBlockModes(KeyProperties.BLOCK_MODE_GCM) - .setKeySize(AES_GCM_KEY_SIZE_IN_BITS) - .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) - .build()); - key = generator.generateKey(); - - sharedPreferences.edit() - .putInt(SHARED_KEY_ANDROID_VERSION_WHEN_KEY_HAS_BEEN_GENERATED, Build.VERSION.SDK_INT) - .apply(); - } - } - } else { - key = readKeyApiL(sharedPreferences, keyStore); - - if (key == null) { - Log.i(TAG, "Generating RSA key pair with keystore"); - final KeyPairGenerator generator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, ANDROID_KEY_STORE_PROVIDER); - final Calendar start = Calendar.getInstance(); - final Calendar end = Calendar.getInstance(); - end.add(Calendar.YEAR, 10); - - generator.initialize( - new KeyPairGeneratorSpec.Builder(context) - .setAlgorithmParameterSpec(new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4)) - .setAlias(RSA_WRAP_LOCAL_PROTECTION_KEY_ALIAS) - .setSubject(new X500Principal("CN=matrix-android-sdk")) - .setStartDate(start.getTime()) - .setEndDate(end.getTime()) - .setSerialNumber(BigInteger.ONE) - .build()); - final KeyPair keyPair = generator.generateKeyPair(); - - Log.i(TAG, "Generating wrapped AES key"); - - final byte[] aesKeyRaw = new byte[AES_GCM_KEY_SIZE_IN_BITS / Byte.SIZE]; - getPrng().nextBytes(aesKeyRaw); - key = new SecretKeySpec(aesKeyRaw, "AES"); - - final Cipher cipher = Cipher.getInstance(RSA_WRAP_CIPHER_TYPE); - cipher.init(Cipher.WRAP_MODE, keyPair.getPublic()); - byte[] wrappedAesKey = cipher.wrap(key); - - sharedPreferences.edit() - .putString(AES_WRAPPED_PROTECTION_KEY_SHARED_PREFERENCE, Base64.encodeToString(wrappedAesKey, 0)) - .putInt(SHARED_KEY_ANDROID_VERSION_WHEN_KEY_HAS_BEEN_GENERATED, Build.VERSION.SDK_INT) - .apply(); - } - } - - sSecretKeyAndVersion = new SecretKeyAndVersion(key, androidVersionWhenTheKeyHasBeenGenerated); - } - - return sSecretKeyAndVersion; - } - - /** - * Read the key, which may have been stored when the OS was < M - * - * @param sharedPreferences shared pref - * @param keyStore key store - * @return the key if it exists or null - */ - @Nullable - private static SecretKey readKeyApiL(SharedPreferences sharedPreferences, KeyStore keyStore) - throws KeyStoreException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, UnrecoverableKeyException { - final String wrappedAesKeyString = sharedPreferences.getString(AES_WRAPPED_PROTECTION_KEY_SHARED_PREFERENCE, null); - if (wrappedAesKeyString != null && keyStore.containsAlias(RSA_WRAP_LOCAL_PROTECTION_KEY_ALIAS)) { - Log.i(TAG, "RSA + wrapped AES local protection keys found in keystore"); - final PrivateKey privateKey = (PrivateKey) keyStore.getKey(RSA_WRAP_LOCAL_PROTECTION_KEY_ALIAS, null); - final byte[] wrappedAesKey = Base64.decode(wrappedAesKeyString, 0); - final Cipher cipher = Cipher.getInstance(RSA_WRAP_CIPHER_TYPE); - cipher.init(Cipher.UNWRAP_MODE, privateKey); - return (SecretKey) cipher.unwrap(wrappedAesKey, "AES", Cipher.SECRET_KEY); - } - - // Key does not exist - return null; - } - - /** - * Returns the unique SecureRandom instance shared for all local storage encryption operations. - */ - private static SecureRandom getPrng() { - if (sPrng == null) { - sPrng = new SecureRandom(); - } - - return sPrng; - } - - /** - * Create a CipherOutputStream instance. - * Before Kitkat, this method will return out as local storage encryption is not implemented for - * devices before KitKat. - * - * @param out the output stream - * @param context the context holding the application shared preferences - */ - @Nullable - public static OutputStream createCipherOutputStream(OutputStream out, Context context) - throws IOException, CertificateException, NoSuchAlgorithmException, - UnrecoverableKeyException, InvalidKeyException, InvalidAlgorithmParameterException, - NoSuchPaddingException, NoSuchProviderException, KeyStoreException, IllegalBlockSizeException { - - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { - return out; - } - - final SecretKeyAndVersion keyAndVersion = getAesGcmLocalProtectionKey(context); - if (keyAndVersion == null || keyAndVersion.getSecretKey() == null) { - throw new KeyStoreException(); - } - - final Cipher cipher = Cipher.getInstance(AES_GCM_CIPHER_TYPE); - byte[] iv; - - if (keyAndVersion.getAndroidVersionWhenTheKeyHasBeenGenerated() >= Build.VERSION_CODES.M) { - cipher.init(Cipher.ENCRYPT_MODE, keyAndVersion.getSecretKey()); - iv = cipher.getIV(); - } else { - iv = new byte[AES_GCM_IV_LENGTH]; - getPrng().nextBytes(iv); - cipher.init(Cipher.ENCRYPT_MODE, keyAndVersion.getSecretKey(), new IvParameterSpec(iv)); - } - - if (iv.length != AES_GCM_IV_LENGTH) { - Log.e(TAG, "Invalid IV length " + iv.length); - return null; - } - - out.write(iv.length); - out.write(iv); - - return new CipherOutputStream(out, cipher); - } - - /** - * Create a CipherInputStream instance. - * Before Kitkat, this method will return `in` because local storage encryption is not implemented for devices before KitKat. - * Warning, if `in` is not an encrypted stream, it's up to the caller to close and reopen `in`, because the stream has been read. - * - * @param in the input stream - * @param context the context holding the application shared preferences - * @return in, or the created InputStream, or null if the InputStream `in` does not contain encrypted data - */ - @Nullable - public static InputStream createCipherInputStream(InputStream in, Context context) - throws NoSuchPaddingException, NoSuchAlgorithmException, CertificateException, - InvalidKeyException, KeyStoreException, UnrecoverableKeyException, IllegalBlockSizeException, - NoSuchProviderException, InvalidAlgorithmParameterException, IOException { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { - return in; - } - - final int iv_len = in.read(); - if (iv_len != AES_GCM_IV_LENGTH) { - Log.e(TAG, "Invalid IV length " + iv_len); - return null; - } - - final byte[] iv = new byte[AES_GCM_IV_LENGTH]; - in.read(iv); - - final Cipher cipher = Cipher.getInstance(AES_GCM_CIPHER_TYPE); - - final SecretKeyAndVersion keyAndVersion = getAesGcmLocalProtectionKey(context); - if (keyAndVersion == null || keyAndVersion.getSecretKey() == null) { - throw new KeyStoreException(); - } - - AlgorithmParameterSpec spec; - - if (keyAndVersion.getAndroidVersionWhenTheKeyHasBeenGenerated() >= Build.VERSION_CODES.M) { - spec = new GCMParameterSpec(AES_GCM_KEY_SIZE_IN_BITS, iv); - } else { - spec = new IvParameterSpec(iv); - } - - cipher.init(Cipher.DECRYPT_MODE, keyAndVersion.getSecretKey(), spec); - - return new CipherInputStream(in, cipher); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/ContentManager.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/ContentManager.java deleted file mode 100644 index 32341d94..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/ContentManager.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.util; - -import android.support.annotation.Nullable; - -import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig; -import im.vector.matrix.android.api.auth.data.Credentials; -import im.vector.matrix.android.internal.legacy.RestClient; - -/** - * Class for accessing content from the current session. - */ -public class ContentManager { - private static final String LOG_TAG = ContentManager.class.getSimpleName(); - - public static final String MATRIX_CONTENT_URI_SCHEME = "mxc://"; - - public static final String METHOD_CROP = "crop"; - public static final String METHOD_SCALE = "scale"; - - public static final String URI_PREFIX_CONTENT_API = "/_matrix/media/v1/"; - - public static final String MATRIX_CONTENT_IDENTICON_PREFIX = "identicon/"; - - // HS config - private final HomeServerConnectionConfig mHsConfig; - private final Credentials mCredentials; - - // the unsent events Manager - private final UnsentEventsManager mUnsentEventsManager; - - // AV scanner handling - private boolean mIsAvScannerEnabled; - private String mDownloadUrlPrefix; - - /** - * Default constructor. - * - * @param hsConfig the HomeserverConnectionConfig to use - * @param unsentEventsManager the unsent events manager - */ - public ContentManager(HomeServerConnectionConfig hsConfig, Credentials credentials, UnsentEventsManager unsentEventsManager) { - mHsConfig = hsConfig; - mCredentials = credentials; - mUnsentEventsManager = unsentEventsManager; - // The AV scanner is disabled by default - configureAntiVirusScanner(false); - } - - /** - * Configure the anti-virus scanner. - * If the anti-virus server url is different than the home server url, - * it must be provided in HomeServerConnectionConfig. - * The home server url is considered by default. - * - * @param isEnabled true to enable the anti-virus scanner, false otherwise. - */ - public void configureAntiVirusScanner(boolean isEnabled) { - mIsAvScannerEnabled = isEnabled; - if (isEnabled) { - mDownloadUrlPrefix = mHsConfig.getAntiVirusServerUri() + "/" + RestClient.URI_API_PREFIX_PATH_MEDIA_PROXY_UNSTABLE; - } else { - mDownloadUrlPrefix = mHsConfig.getHomeServerUri() + URI_PREFIX_CONTENT_API; - } - } - - public boolean isAvScannerEnabled() { - return mIsAvScannerEnabled; - } - - /** - * @return the hs config. - */ - public HomeServerConnectionConfig getHsConfig() { - return mHsConfig; - } - - /** - * @return the getCredentials. - */ - public Credentials getCredentials() { - return mCredentials; - } - - /** - * @return the unsent events manager - */ - public UnsentEventsManager getUnsentEventsManager() { - return mUnsentEventsManager; - } - - /** - * Compute the identicon URL for an userId. - * - * @param userId the user id. - * @return the url - */ - public static String getIdenticonURL(String userId) { - // sanity check - if (null != userId) { - String urlEncodedUser = null; - try { - urlEncodedUser = java.net.URLEncoder.encode(userId, "UTF-8"); - } catch (Exception e) { - Log.e(LOG_TAG, "## getIdenticonURL() : java.net.URLEncoder.encode failed " + e.getMessage(), e); - } - - return ContentManager.MATRIX_CONTENT_URI_SCHEME + MATRIX_CONTENT_IDENTICON_PREFIX + urlEncodedUser; - } - - return null; - } - - /** - * Check whether an url is a valid matrix content url. - * - * @param contentUrl the content URL (in the form of "mxc://..."). - * @return true if contentUrl is valid. - */ - public static boolean isValidMatrixContentUrl(String contentUrl) { - return (null != contentUrl && contentUrl.startsWith(MATRIX_CONTENT_URI_SCHEME)); - } - - /** - * Returns the task identifier used to download the content at a Matrix media content URI - * (in the form of "mxc://..."). - * - * @param contentUrl the matrix content url. - * @return the task identifier, or null if the url is invalid.. - */ - @Nullable - public String downloadTaskIdForMatrixMediaContent(String contentUrl) { - if (isValidMatrixContentUrl(contentUrl)) { - // We extract the server name and the media id from the matrix content url - // to define a unique download task id - return contentUrl.substring(MATRIX_CONTENT_URI_SCHEME.length()); - } - - // do not allow non-mxc content URLs: we should not be making requests out to whatever - // http urls people send us - return null; - } - - /** - * Get the actual URL for accessing the full-size image of a Matrix media content URI. - * - * @param contentUrl the Matrix media content URI (in the form of "mxc://..."). - * @return the URL to access the described resource, or null if the url is invalid. - * @deprecated See getDownloadableUrl(contentUrl, isEncrypted). - */ - @Nullable - public String getDownloadableUrl(String contentUrl) { - // Suppose here by default that the content is not encrypted. - // FIXME this method should be removed as soon as possible - return getDownloadableUrl(contentUrl, false); - } - - /** - * Get the actual URL for accessing the full-size image of a Matrix media content URI. - * - * @param contentUrl the Matrix media content URI (in the form of "mxc://..."). - * @param isEncrypted tell whether the related content is encrypted (This information is - * required when the anti-virus scanner is enabled). - * @return the URL to access the described resource, or null if the url is invalid. - */ - @Nullable - public String getDownloadableUrl(String contentUrl, boolean isEncrypted) { - if (isValidMatrixContentUrl(contentUrl)) { - if (!isEncrypted || !mIsAvScannerEnabled) { - String mediaServerAndId = contentUrl.substring(MATRIX_CONTENT_URI_SCHEME.length()); - return mDownloadUrlPrefix + "download/" + mediaServerAndId; - } else { - // In case of encrypted content, a unique url is used when the scanner is enabled - // The encryption info must be sent in the body of the request. - return mDownloadUrlPrefix + "download_encrypted"; - } - } - - // do not allow non-mxc content URLs - return null; - } - - /** - * Get the actual URL for accessing the thumbnail image of a given Matrix media content URI. - * - * @param contentUrl the Matrix media content URI (in the form of "mxc://..."). - * @param width the desired width - * @param height the desired height - * @param method the desired scale method (METHOD_CROP or METHOD_SCALE) - * @return the URL to access the described resource, or null if the url is invalid. - */ - @Nullable - public String getDownloadableThumbnailUrl(String contentUrl, int width, int height, String method) { - if (isValidMatrixContentUrl(contentUrl)) { - String mediaServerAndId = contentUrl.substring(MATRIX_CONTENT_URI_SCHEME.length()); - - // ignore the #auto pattern - if (mediaServerAndId.endsWith("#auto")) { - mediaServerAndId = mediaServerAndId.substring(0, mediaServerAndId.length() - "#auto".length()); - } - - // Build the thumbnail url. - String url; - // Caution: identicon has no thumbnail path. - if (mediaServerAndId.startsWith(MATRIX_CONTENT_IDENTICON_PREFIX)) { - // identicon url still go to the media repo since they don’t need virus scanning - url = mHsConfig.getHomeServerUri().toString() + URI_PREFIX_CONTENT_API; - } else { - // Use the current download url prefix to take into account a potential antivirus scanner - url = mDownloadUrlPrefix + "thumbnail/"; - } - - url += mediaServerAndId; - url += "?width=" + width; - url += "&height=" + height; - url += "&method=" + method; - return url; - } - - // do not allow non-mxc content URLs - return null; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/ContentUtils.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/ContentUtils.java deleted file mode 100644 index 2eb33163..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/ContentUtils.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.util; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; - -import android.os.Build; -import android.os.StatFs; -import android.system.Os; -import android.webkit.MimeTypeMap; - -import im.vector.matrix.android.internal.legacy.rest.model.message.ImageInfo; - -import java.io.File; -import java.lang.reflect.Field; -import java.lang.reflect.Method; - -/** - * Static content utility methods. - */ -public class ContentUtils { - private static final String LOG_TAG = ContentUtils.class.getSimpleName(); - - /** - * Build an ImageInfo object based on the image at the given path. - * - * @param filePath the path to the image in storage - * @return the image info - */ - public static ImageInfo getImageInfoFromFile(String filePath) { - ImageInfo imageInfo = new ImageInfo(); - try { - Bitmap imageBitmap = BitmapFactory.decodeFile(filePath); - imageInfo.w = imageBitmap.getWidth(); - imageInfo.h = imageBitmap.getHeight(); - - File file = new File(filePath); - imageInfo.size = file.length(); - - imageInfo.mimetype = getMimeType(filePath); - } catch (OutOfMemoryError oom) { - Log.e(LOG_TAG, "## getImageInfoFromFile() : oom", oom); - } - - return imageInfo; - } - - public static String getMimeType(String filePath) { - MimeTypeMap mime = MimeTypeMap.getSingleton(); - return mime.getMimeTypeFromExtension(filePath.substring(filePath.lastIndexOf('.') + 1).toLowerCase()); - } - - /** - * Delete a directory with its content - * - * @param directory the base directory - * @return true if the directory is deleted - */ - public static boolean deleteDirectory(File directory) { - // sanity check - if (null == directory) { - return false; - } - - boolean succeed = true; - - if (directory.exists()) { - File[] files = directory.listFiles(); - - if (null != files) { - for (int i = 0; i < files.length; i++) { - if (files[i].isDirectory()) { - succeed &= deleteDirectory(files[i]); - } else { - succeed &= files[i].delete(); - } - } - } - } - - return succeed && directory.delete(); - } - - /** - * Recursive method to compute a directory size - * - * @param context the context - * @param directory the directory - * @param logPathDepth the depth to log - * @return the directory size - */ - @SuppressLint("deprecation") - public static long getDirectorySize(Context context, File directory, int logPathDepth) { - StatFs statFs = new StatFs(directory.getAbsolutePath()); - long blockSize; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - blockSize = statFs.getBlockSizeLong(); - } else { - blockSize = statFs.getBlockSize(); - } - - if (blockSize < 0) { - blockSize = 1; - } - - return getDirectorySize(context, directory, logPathDepth, blockSize); - } - - /** - * Recursive method to compute a directory size - * - * @param context the context - * @param directory the directory - * @param logPathDepth the depth to log - * @param blockSize the filesystem block size - * @return the directory size - */ - public static long getDirectorySize(Context context, File directory, int logPathDepth, long blockSize) { - long size = 0; - - File[] files = directory.listFiles(); - - if (null != files) { - for (int i = 0; i < files.length; i++) { - File file = files[i]; - - if (!file.isDirectory()) { - size += (file.length() / blockSize + 1) * blockSize; - } else { - size += getDirectorySize(context, file, logPathDepth - 1); - } - } - } - - if (logPathDepth > 0) { - Log.d(LOG_TAG, "## getDirectorySize() " + directory.getPath() + " " + android.text.format.Formatter.formatFileSize(context, size)); - } - - return size; - } - - @SuppressLint("NewApi") - public static long getLastAccessTime(File file) { - long lastAccessTime = file.lastModified(); - - try { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - lastAccessTime = Os.lstat(file.getAbsolutePath()).st_atime; - } else { - Class clazz = Class.forName("libcore.io.Libcore"); - Field field = clazz.getDeclaredField("os"); - if (!field.isAccessible()) { - field.setAccessible(true); - } - Object os = field.get(null); - - Method method = os.getClass().getMethod("lstat", String.class); - Object lstat = method.invoke(os, file.getAbsolutePath()); - - field = lstat.getClass().getDeclaredField("st_atime"); - if (!field.isAccessible()) { - field.setAccessible(true); - } - lastAccessTime = field.getLong(lstat); - } - } catch (Exception e) { - Log.e(LOG_TAG, "## getLastAccessTime() failed " + e.getMessage() + " for file " + file, e); - } - return lastAccessTime; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/EventDisplay.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/EventDisplay.java deleted file mode 100644 index 7d09f771..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/EventDisplay.java +++ /dev/null @@ -1,620 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.util; - -import android.content.Context; -import android.graphics.Typeface; -import android.os.Build; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.text.Html; -import android.text.Spannable; -import android.text.SpannableString; -import android.text.SpannableStringBuilder; -import android.text.TextUtils; -import android.text.style.ForegroundColorSpan; -import android.text.style.StyleSpan; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; - -import im.vector.matrix.android.R; -import im.vector.matrix.android.internal.legacy.call.MXCallsManager; -import im.vector.matrix.android.internal.legacy.crypto.MXCryptoError; -import im.vector.matrix.android.internal.legacy.data.RoomState; -import im.vector.matrix.android.internal.legacy.interfaces.HtmlToolbox; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.EventContent; -import im.vector.matrix.android.internal.legacy.rest.model.RedactedBecause; -import im.vector.matrix.android.internal.legacy.rest.model.RoomMember; -import im.vector.matrix.android.internal.legacy.rest.model.message.Message; -import im.vector.matrix.android.internal.legacy.rest.model.pid.RoomThirdPartyInvite; - -/** - * Class helper to stringify an event - */ -public class EventDisplay { - private static final String LOG_TAG = EventDisplay.class.getSimpleName(); - - private static final String MESSAGE_IN_REPLY_TO_FIRST_PART = "
"; - private static final String MESSAGE_IN_REPLY_TO_LAST_PART = ""; - - // members - protected final Event mEvent; - protected final Context mContext; - protected final RoomState mRoomState; - - @Nullable - protected final HtmlToolbox mHtmlToolbox; - - protected boolean mPrependAuthor; - - // let the application defines if the redacted events must be displayed - public static final boolean mDisplayRedactedEvents = false; - - // constructor - public EventDisplay(Context context, Event event, RoomState roomState) { - this(context, event, roomState, null); - } - - // constructor - public EventDisplay(Context context, Event event, RoomState roomState, @Nullable HtmlToolbox htmlToolbox) { - mContext = context.getApplicationContext(); - mEvent = event; - mRoomState = roomState; - mHtmlToolbox = htmlToolbox; - } - - /** - *

Prepend the text with the author's name if they have not been mentioned in the text.

- * This will prepend text messages with the author's name. This will NOT prepend things like - * emote, room topic changes, etc which already mention the author's name in the message. - * - * @param prepend true to prepend the message author. - */ - public void setPrependMessagesWithAuthor(boolean prepend) { - mPrependAuthor = prepend; - } - - /** - * Compute an "human readable" name for an user Id. - * - * @param userId the user id - * @param roomState the room state - * @return the user display name - */ - protected static String getUserDisplayName(String userId, RoomState roomState) { - if (null != roomState) { - return roomState.getMemberName(userId); - } else { - return userId; - } - } - - /** - * Stringify the linked event. - * - * @return The text or null if it isn't possible. - */ - public CharSequence getTextualDisplay() { - return getTextualDisplay(null); - } - - /** - * Stringify the linked event. - * - * @param displayNameColor the display name highlighted color. - * @return The text or null if it isn't possible. - */ - public CharSequence getTextualDisplay(Integer displayNameColor) { - CharSequence text = null; - - try { - JsonObject jsonEventContent = mEvent.getContentAsJsonObject(); - - String userDisplayName = getUserDisplayName(mEvent.getSender(), mRoomState); - String eventType = mEvent.getType(); - - if (mEvent.isCallEvent()) { - if (Event.EVENT_TYPE_CALL_INVITE.equals(eventType)) { - boolean isVideo = false; - // detect call type from the sdp - try { - JsonObject offer = jsonEventContent.get("offer").getAsJsonObject(); - JsonElement sdp = offer.get("sdp"); - String sdpValue = sdp.getAsString(); - isVideo = sdpValue.contains("m=video"); - } catch (Exception e) { - Log.e(LOG_TAG, "getTextualDisplay : " + e.getMessage(), e); - } - - if (isVideo) { - return mContext.getString(R.string.notice_placed_video_call, userDisplayName); - } else { - return mContext.getString(R.string.notice_placed_voice_call, userDisplayName); - } - } else if (Event.EVENT_TYPE_CALL_ANSWER.equals(eventType)) { - return mContext.getString(R.string.notice_answered_call, userDisplayName); - } else if (Event.EVENT_TYPE_CALL_HANGUP.equals(eventType)) { - return mContext.getString(R.string.notice_ended_call, userDisplayName); - } else { - return eventType; - } - } else if (Event.EVENT_TYPE_STATE_HISTORY_VISIBILITY.equals(eventType)) { - CharSequence subpart; - String historyVisibility = (null != jsonEventContent.get("history_visibility")) ? - jsonEventContent.get("history_visibility").getAsString() : RoomState.HISTORY_VISIBILITY_SHARED; - - if (TextUtils.equals(historyVisibility, RoomState.HISTORY_VISIBILITY_SHARED)) { - subpart = mContext.getString(R.string.notice_room_visibility_shared); - } else if (TextUtils.equals(historyVisibility, RoomState.HISTORY_VISIBILITY_INVITED)) { - subpart = mContext.getString(R.string.notice_room_visibility_invited); - } else if (TextUtils.equals(historyVisibility, RoomState.HISTORY_VISIBILITY_JOINED)) { - subpart = mContext.getString(R.string.notice_room_visibility_joined); - } else if (TextUtils.equals(historyVisibility, RoomState.HISTORY_VISIBILITY_WORLD_READABLE)) { - subpart = mContext.getString(R.string.notice_room_visibility_world_readable); - } else { - subpart = mContext.getString(R.string.notice_room_visibility_unknown, historyVisibility); - } - - text = mContext.getString(R.string.notice_made_future_room_visibility, userDisplayName, subpart); - } else if (Event.EVENT_TYPE_RECEIPT.equals(eventType)) { - // the read receipt should not be displayed - text = "Read Receipt"; - } else if (Event.EVENT_TYPE_MESSAGE.equals(eventType)) { - final String msgtype = (null != jsonEventContent.get("msgtype")) ? jsonEventContent.get("msgtype").getAsString() : ""; - // all m.room.message events should support the 'body' key fallback, so use it. - - text = jsonEventContent.has("body") ? jsonEventContent.get("body").getAsString() : null; - // check for html formatting - if (jsonEventContent.has("formatted_body") && jsonEventContent.has("format")) { - text = getFormattedMessage(mContext, jsonEventContent, mHtmlToolbox); - } - // avoid empty image name - if (TextUtils.equals(msgtype, Message.MSGTYPE_IMAGE) && TextUtils.isEmpty(text)) { - text = mContext.getString(R.string.summary_user_sent_image, userDisplayName); - } else if (TextUtils.equals(msgtype, Message.MSGTYPE_EMOTE)) { - text = "* " + userDisplayName + " " + text; - } else if (TextUtils.isEmpty(text)) { - text = ""; - } else if (mPrependAuthor) { - text = new SpannableStringBuilder(mContext.getString(R.string.summary_message, userDisplayName, text)); - - if (null != displayNameColor) { - ((SpannableStringBuilder) text).setSpan(new ForegroundColorSpan(displayNameColor), - 0, userDisplayName.length() + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - ((SpannableStringBuilder) text).setSpan(new StyleSpan(Typeface.BOLD), - 0, userDisplayName.length() + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - } - } - } else if (Event.EVENT_TYPE_STICKER.equals(eventType)) { - // all m.stickers events should support the 'body' key fallback, so use it. - text = jsonEventContent.has("body") ? jsonEventContent.get("body").getAsString() : null; - - if (TextUtils.isEmpty(text)) { - text = mContext.getString(R.string.summary_user_sent_sticker, userDisplayName); - } - - } else if (Event.EVENT_TYPE_MESSAGE_ENCRYPTION.equals(eventType)) { - text = mContext.getString(R.string.notice_end_to_end, userDisplayName, mEvent.getWireEventContent().algorithm); - } else if (Event.EVENT_TYPE_MESSAGE_ENCRYPTED.equals(eventType)) { - // don't display - if (mEvent.isRedacted()) { - String redactedInfo = EventDisplay.getRedactionMessage(mContext, mEvent, mRoomState); - - if (TextUtils.isEmpty(redactedInfo)) { - return null; - } else { - return redactedInfo; - } - } else { - String message = null; - - - if (null != mEvent.getCryptoError()) { - String errorDescription; - - MXCryptoError error = mEvent.getCryptoError(); - - if (TextUtils.equals(error.errcode, MXCryptoError.UNKNOWN_INBOUND_SESSION_ID_ERROR_CODE)) { - errorDescription = mContext.getResources().getString(R.string.notice_crypto_error_unkwown_inbound_session_id); - } else { - errorDescription = error.getLocalizedMessage(); - } - - message = mContext.getString(R.string.notice_crypto_unable_to_decrypt, errorDescription); - } - - if (TextUtils.isEmpty(message)) { - message = mContext.getString(R.string.encrypted_message); - } - - SpannableString spannableStr = new SpannableString(message); - spannableStr.setSpan(new StyleSpan(Typeface.ITALIC), 0, message.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - text = spannableStr; - } - } else if (Event.EVENT_TYPE_STATE_ROOM_TOPIC.equals(eventType)) { - String topic = jsonEventContent.getAsJsonPrimitive("topic").getAsString(); - - if (mEvent.isRedacted()) { - String redactedInfo = EventDisplay.getRedactionMessage(mContext, mEvent, mRoomState); - - if (TextUtils.isEmpty(redactedInfo)) { - return null; - } - - topic = redactedInfo; - } - - if (!TextUtils.isEmpty(topic)) { - text = mContext.getString(R.string.notice_topic_changed, userDisplayName, topic); - } else { - text = mContext.getString(R.string.notice_room_topic_removed, userDisplayName); - } - } else if (Event.EVENT_TYPE_STATE_ROOM_NAME.equals(eventType)) { - JsonPrimitive nameAsJson = jsonEventContent.getAsJsonPrimitive("name"); - String roomName = (null == nameAsJson) ? null : nameAsJson.getAsString(); - - if (mEvent.isRedacted()) { - String redactedInfo = EventDisplay.getRedactionMessage(mContext, mEvent, mRoomState); - - if (TextUtils.isEmpty(redactedInfo)) { - return null; - } - - roomName = redactedInfo; - } - - if (!TextUtils.isEmpty(roomName)) { - text = mContext.getString(R.string.notice_room_name_changed, userDisplayName, roomName); - } else { - text = mContext.getString(R.string.notice_room_name_removed, userDisplayName); - } - } else if (Event.EVENT_TYPE_STATE_ROOM_THIRD_PARTY_INVITE.equals(eventType)) { - RoomThirdPartyInvite invite = JsonUtils.toRoomThirdPartyInvite(mEvent.getContent()); - String displayName = invite.display_name; - - if (mEvent.isRedacted()) { - String redactedInfo = EventDisplay.getRedactionMessage(mContext, mEvent, mRoomState); - - if (TextUtils.isEmpty(redactedInfo)) { - return null; - } - - displayName = redactedInfo; - } - - text = mContext.getString(R.string.notice_room_third_party_invite, userDisplayName, displayName); - } else if (Event.EVENT_TYPE_STATE_ROOM_MEMBER.equals(eventType)) { - text = getMembershipNotice(mContext, mEvent, mRoomState); - } - } catch (Exception e) { - Log.e(LOG_TAG, "getTextualDisplay() " + e.getMessage(), e); - } - - return text; - } - - /** - * Compute the redact text for an event. - * - * @param context the context - * @param event the event - * @param roomState the room state - * @return the redacted event text - */ - public static String getRedactionMessage(Context context, Event event, RoomState roomState) { - // test if the redacted event must be displayed. - if (!mDisplayRedactedEvents) { - return null; - } - - // Check first whether the event has been redacted - String redactedInfo = null; - - if (event.isRedacted() && (null != roomState)) { - RedactedBecause redactedBecause = event.unsigned.redacted_because; - String redactedBy = redactedBecause.sender; - String redactedReason = null; - - if (null != redactedBecause.content) { - redactedReason = redactedBecause.content.reason; - } - - if (!TextUtils.isEmpty(redactedReason)) { - if (!TextUtils.isEmpty(redactedBy)) { - redactedBy = context.getString(R.string.notice_event_redacted_by, redactedBy) - + context.getString(R.string.notice_event_redacted_reason, redactedReason); - } else { - redactedBy = context.getString(R.string.notice_event_redacted_reason, redactedReason); - } - } else if (!TextUtils.isEmpty(redactedBy)) { - redactedBy = context.getString(R.string.notice_event_redacted_by, redactedBy); - } - - redactedInfo = context.getString(R.string.notice_event_redacted, redactedBy); - } - - return redactedInfo; - } - - /** - * Compute the sender display name - * - * @param event the event - * @param eventContent the event content - * @param prevEventContent the prev event content - * @param roomState the room state - * @return the "human readable" display name - */ - protected static String senderDisplayNameForEvent(Event event, EventContent eventContent, EventContent prevEventContent, RoomState roomState) { - String senderDisplayName = event.getSender(); - - if (!event.isRedacted()) { - if (null != roomState) { - // Consider first the current display name defined in provided room state - // (Note: this room state is supposed to not take the new event into account) - senderDisplayName = roomState.getMemberName(event.getSender()); - } - - // Check whether this sender name is updated by the current event (This happens in case of new joined member) - if ((null != eventContent) && TextUtils.equals(RoomMember.MEMBERSHIP_JOIN, eventContent.membership)) { - // detect if it is displayname update - // a display name update is detected when the previous state was join and there was a displayname - if (!TextUtils.isEmpty(eventContent.displayname) - || ((null != prevEventContent) - && TextUtils.equals(RoomMember.MEMBERSHIP_JOIN, prevEventContent.membership) - && !TextUtils.isEmpty(prevEventContent.displayname))) { - senderDisplayName = eventContent.displayname; - } - } - } - - return senderDisplayName; - } - - /** - * Build a membership notice text from its dedicated event. - * - * @param context the context. - * @param event the event. - * @param roomState the room state. - * @return the membership text. - */ - public static String getMembershipNotice(Context context, Event event, RoomState roomState) { - JsonObject content = event.getContentAsJsonObject(); - - // don't support redacted membership event - if ((null == content) || (content.entrySet().size() == 0)) { - return null; - } - - EventContent eventContent = JsonUtils.toEventContent(event.getContentAsJsonObject()); - EventContent prevEventContent = event.getPrevContent(); - - String senderDisplayName = senderDisplayNameForEvent(event, eventContent, prevEventContent, roomState); - String prevUserDisplayName = null; - - String prevMembership = null; - - if (null != prevEventContent) { - prevMembership = prevEventContent.membership; - } - - if ((null != prevEventContent)) { - prevUserDisplayName = prevEventContent.displayname; - } - - // use by default the provided display name - String targetDisplayName = eventContent.displayname; - - // if it is not provided, use the stateKey value - // and try to retrieve a valid display name - if (null == targetDisplayName) { - targetDisplayName = event.stateKey; - if ((null != targetDisplayName) && (null != roomState) && !event.isRedacted()) { - targetDisplayName = roomState.getMemberName(targetDisplayName); - } - } - - // Check whether the sender has updated his profile (the membership is then unchanged) - if (TextUtils.equals(prevMembership, eventContent.membership)) { - String redactedInfo = EventDisplay.getRedactionMessage(context, event, roomState); - - // Is redacted event? - if (event.isRedacted()) { - - // Here the event is ignored (no display) - if (null == redactedInfo) { - return null; - } - - return context.getString(R.string.notice_profile_change_redacted, senderDisplayName, redactedInfo); - } else { - String displayText = ""; - - if (!TextUtils.equals(senderDisplayName, prevUserDisplayName)) { - if (TextUtils.isEmpty(prevUserDisplayName)) { - if (!TextUtils.equals(event.getSender(), senderDisplayName)) { - displayText = context.getString(R.string.notice_display_name_set, event.getSender(), senderDisplayName); - } - } else if (TextUtils.isEmpty(senderDisplayName)) { - displayText = context.getString(R.string.notice_display_name_removed, event.getSender(), prevUserDisplayName); - } else { - displayText = context.getString(R.string.notice_display_name_changed_from, event.getSender(), prevUserDisplayName, senderDisplayName); - } - } - - // Check whether the avatar has been changed - String avatar = eventContent.avatar_url; - String prevAvatar = null; - - if (null != prevEventContent) { - prevAvatar = prevEventContent.avatar_url; - } - - if (!TextUtils.equals(prevAvatar, avatar)) { - if (!TextUtils.isEmpty(displayText)) { - displayText = displayText + " " + context.getString(R.string.notice_avatar_changed_too); - } else { - displayText = context.getString(R.string.notice_avatar_url_changed, senderDisplayName); - } - } - - return displayText; - } - } else if (RoomMember.MEMBERSHIP_INVITE.equals(eventContent.membership)) { - if (null != eventContent.third_party_invite) { - return context.getString(R.string.notice_room_third_party_registered_invite, targetDisplayName, eventContent.third_party_invite.display_name); - } else { - String selfUserId = null; - - if ((null != roomState) && (null != roomState.getDataHandler())) { - selfUserId = roomState.getDataHandler().getUserId(); - } - - if (TextUtils.equals(event.stateKey, selfUserId)) { - return context.getString(R.string.notice_room_invite_you, senderDisplayName); - } - - if (null == event.stateKey) { - return context.getString(R.string.notice_room_invite_no_invitee, senderDisplayName); - } - - // conference call case - if (targetDisplayName.equals(MXCallsManager.getConferenceUserId(event.roomId))) { - return context.getString(R.string.notice_requested_voip_conference, senderDisplayName); - } - - return context.getString(R.string.notice_room_invite, senderDisplayName, targetDisplayName); - } - } else if (RoomMember.MEMBERSHIP_JOIN.equals(eventContent.membership)) { - // conference call case - if (TextUtils.equals(event.sender, MXCallsManager.getConferenceUserId(event.roomId))) { - return context.getString(R.string.notice_voip_started); - } - - return context.getString(R.string.notice_room_join, senderDisplayName); - } else if (RoomMember.MEMBERSHIP_LEAVE.equals(eventContent.membership)) { - // conference call case - if (TextUtils.equals(event.sender, MXCallsManager.getConferenceUserId(event.roomId))) { - return context.getString(R.string.notice_voip_finished); - } - - // 2 cases here: this member may have left voluntarily or they may have been "left" by someone else ie. kicked - if (TextUtils.equals(event.getSender(), event.stateKey)) { - if ((null != prevEventContent) && TextUtils.equals(prevEventContent.membership, RoomMember.MEMBERSHIP_INVITE)) { - return context.getString(R.string.notice_room_reject, senderDisplayName); - } else { - - // use the latest known displayname - if ((null == eventContent.displayname) && (null != prevUserDisplayName)) { - senderDisplayName = prevUserDisplayName; - } - - return context.getString(R.string.notice_room_leave, senderDisplayName); - } - - } else if (null != prevMembership) { - if (prevMembership.equals(RoomMember.MEMBERSHIP_INVITE)) { - return context.getString(R.string.notice_room_withdraw, senderDisplayName, targetDisplayName); - } else if (prevMembership.equals(RoomMember.MEMBERSHIP_JOIN)) { - return context.getString(R.string.notice_room_kick, senderDisplayName, targetDisplayName); - } else if (prevMembership.equals(RoomMember.MEMBERSHIP_BAN)) { - return context.getString(R.string.notice_room_unban, senderDisplayName, targetDisplayName); - } - } - } else if (RoomMember.MEMBERSHIP_BAN.equals(eventContent.membership)) { - return context.getString(R.string.notice_room_ban, senderDisplayName, targetDisplayName); - } else if (RoomMember.MEMBERSHIP_KICK.equals(eventContent.membership)) { - return context.getString(R.string.notice_room_kick, senderDisplayName, targetDisplayName); - } else { - Log.e(LOG_TAG, "Unknown membership: " + eventContent.membership); - } - return null; - } - - - /** - * @param context the context - * @param jsonEventContent the current jsonEventContent - * @param htmlToolbox an optional htmlToolbox to manage html images and tag - * @return the formatted message as CharSequence - */ - private CharSequence getFormattedMessage(@NonNull final Context context, - @NonNull final JsonObject jsonEventContent, - @Nullable final HtmlToolbox htmlToolbox) { - final String format = jsonEventContent.getAsJsonPrimitive("format").getAsString(); - CharSequence text = null; - if (Message.FORMAT_MATRIX_HTML.equals(format)) { - String htmlBody = jsonEventContent.getAsJsonPrimitive("formatted_body").getAsString(); - if (htmlToolbox != null) { - htmlBody = htmlToolbox.convert(htmlBody); - } - // Special treatment for "In reply to" message - if (jsonEventContent.has("m.relates_to")) { - final JsonElement relatesTo = jsonEventContent.get("m.relates_to"); - if (relatesTo.isJsonObject()) { - if (relatesTo.getAsJsonObject().has("m.in_reply_to")) { - // Note: tag has been removed by HtmlToolbox.convert() - - // Replace
In reply to - // By
['In reply to' from resources] - // To disable the link and to localize the "In reply to" string - if (htmlBody.startsWith(MESSAGE_IN_REPLY_TO_FIRST_PART)) { - final int index = htmlBody.indexOf(MESSAGE_IN_REPLY_TO_LAST_PART); - if (index != -1) { - htmlBody = MESSAGE_IN_REPLY_TO_FIRST_PART - + context.getString(R.string.message_reply_to_prefix) - + htmlBody.substring(index + MESSAGE_IN_REPLY_TO_LAST_PART.length()); - } - } - } - } - } - // some markers are not supported so fallback on an ascii display until to find the right way to manage them - // an issue has been created https://github.com/vector-im/vector-android/issues/38 - // BMA re-enable
    and
  1. support (https://github.com/vector-im/riot-android/issues/2184) - if (!TextUtils.isEmpty(htmlBody)) { - final Html.ImageGetter imageGetter; - final Html.TagHandler tagHandler; - if (htmlToolbox != null) { - imageGetter = htmlToolbox.getImageGetter(); - tagHandler = htmlToolbox.getTagHandler(htmlBody); - } else { - imageGetter = null; - tagHandler = null; - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - text = Html.fromHtml(htmlBody, - Html.FROM_HTML_SEPARATOR_LINE_BREAK_LIST_ITEM | Html.FROM_HTML_SEPARATOR_LINE_BREAK_LIST, - imageGetter, tagHandler); - } else { - text = Html.fromHtml(htmlBody, imageGetter, tagHandler); - } - // fromHtml formats quotes (> character) with two newlines at the end - // remove any newlines at the end of the CharSequence - while (text.charAt(text.length() - 1) == '\n') { - text = text.subSequence(0, text.length() - 2); - } - } - } - return text; - } - -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/EventUtils.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/EventUtils.java deleted file mode 100644 index ea23cbc7..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/EventUtils.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.util; - -import android.text.TextUtils; - -import im.vector.matrix.android.internal.legacy.MXSession; -import im.vector.matrix.android.internal.legacy.data.Room; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.RoomDirectoryVisibility; -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.BingRule; - -import java.util.regex.Pattern; - -/** - * Utility methods for events. - */ -public class EventUtils { - private static final String LOG_TAG = EventUtils.class.getSimpleName(); - - /** - * Whether the given event should be highlighted in its chat room. - * - * @param session the session. - * @param event the event - * @return whether the event is important and should be highlighted - */ - public static boolean shouldHighlight(MXSession session, Event event) { - // sanity check - if ((null == session) || (null == event)) { - return false; - } - - boolean res = false; - - // search if the event fulfills a rule - BingRule rule = session.fulfillRule(event); - - if (null != rule) { - res = rule.shouldHighlight(); - - if (res) { - Log.d(LOG_TAG, "## shouldHighlight() : the event " + event.roomId + "/" + event.eventId + " is higlighted by " + rule); - } - } - - return res; - } - - /** - * Whether the given event should trigger a notification. - * - * @param session the current matrix session - * @param event the event - * @param activeRoomID the RoomID of disaplyed roomActivity - * @return true if the event should trigger a notification - */ - public static boolean shouldNotify(MXSession session, Event event, String activeRoomID) { - if ((null == event) || (null == session)) { - Log.e(LOG_TAG, "shouldNotify invalid params"); - return false; - } - - // Only room events trigger notifications - if (null == event.roomId) { - Log.e(LOG_TAG, "shouldNotify null room ID"); - return false; - } - - if (null == event.getSender()) { - Log.e(LOG_TAG, "shouldNotify null room ID"); - return false; - } - - // No notification if the user is currently viewing the room - if (TextUtils.equals(event.roomId, activeRoomID)) { - return false; - } - - if (shouldHighlight(session, event)) { - return true; - } - - Room room = session.getDataHandler().getRoom(event.roomId); - return RoomDirectoryVisibility.DIRECTORY_VISIBILITY_PRIVATE.equals(room.getVisibility()) - && !TextUtils.equals(event.getSender(), session.getCredentials().getUserId()); - } - - /** - * Returns whether a string contains an occurrence of another, as a standalone word, regardless of case. - * - * @param subString the string to search for - * @param longString the string to search in - * @return whether a match was found - */ - public static boolean caseInsensitiveFind(String subString, String longString) { - // add sanity checks - if (TextUtils.isEmpty(subString) || TextUtils.isEmpty(longString)) { - return false; - } - - boolean res = false; - - try { - Pattern pattern = Pattern.compile("(\\W|^)" + Pattern.quote(subString) + "(\\W|$)", Pattern.CASE_INSENSITIVE); - res = pattern.matcher(longString).find(); - } catch (Exception e) { - Log.e(LOG_TAG, "## caseInsensitiveFind() : failed", e); - } - - return res; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/FilterUtil.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/FilterUtil.java deleted file mode 100644 index 27af8db4..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/FilterUtil.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.util; - -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; - -import im.vector.matrix.android.internal.legacy.rest.model.filter.Filter; -import im.vector.matrix.android.internal.legacy.rest.model.filter.FilterBody; -import im.vector.matrix.android.internal.legacy.rest.model.filter.RoomEventFilter; -import im.vector.matrix.android.internal.legacy.rest.model.filter.RoomFilter; - -import java.util.ArrayList; - -public class FilterUtil { - - /** - * Patch the filterBody to enable or disable the data save mode - *

    - * If data save mode is on, FilterBody will contains - * "{\"room\": {\"ephemeral\": {\"types\": [\"m.receipt\"]}}, \"presence\":{\"notTypes\": [\"*\"]}}" - * - * @param filterBody filterBody to patch - * @param useDataSaveMode true to enable data save mode - */ - public static void enableDataSaveMode(@NonNull FilterBody filterBody, boolean useDataSaveMode) { - if (useDataSaveMode) { - // Enable data save mode - if (filterBody.room == null) { - filterBody.room = new RoomFilter(); - } - if (filterBody.room.ephemeral == null) { - filterBody.room.ephemeral = new RoomEventFilter(); - } - if (filterBody.room.ephemeral.types == null) { - filterBody.room.ephemeral.types = new ArrayList<>(); - } - if (!filterBody.room.ephemeral.types.contains("m.receipt")) { - filterBody.room.ephemeral.types.add("m.receipt"); - } - - if (filterBody.presence == null) { - filterBody.presence = new Filter(); - } - if (filterBody.presence.notTypes == null) { - filterBody.presence.notTypes = new ArrayList<>(); - } - if (!filterBody.presence.notTypes.contains("*")) { - filterBody.presence.notTypes.add("*"); - } - } else { - if (filterBody.room != null - && filterBody.room.ephemeral != null - && filterBody.room.ephemeral.types != null) { - filterBody.room.ephemeral.types.remove("m.receipt"); - - if (filterBody.room.ephemeral.types.isEmpty()) { - filterBody.room.ephemeral.types = null; - } - - if (!filterBody.room.ephemeral.hasData()) { - filterBody.room.ephemeral = null; - } - - if (!filterBody.room.hasData()) { - filterBody.room = null; - } - } - - if (filterBody.presence != null - && filterBody.presence.notTypes != null) { - filterBody.presence.notTypes.remove("*"); - - if (filterBody.presence.notTypes.isEmpty()) { - filterBody.presence.notTypes = null; - } - - if (!filterBody.presence.hasData()) { - filterBody.presence = null; - } - } - } - } - - /** - * Patch the filterBody to enable or disable the lazy loading - *

    - * If lazy loading is on, the filterBody will looks like - * {"room":{"state":{"lazy_load_members":true})} - * - * @param filterBody filterBody to patch - * @param useLazyLoading true to enable lazy loading - */ - public static void enableLazyLoading(FilterBody filterBody, boolean useLazyLoading) { - if (useLazyLoading) { - // Enable lazy loading - if (filterBody.room == null) { - filterBody.room = new RoomFilter(); - } - if (filterBody.room.state == null) { - filterBody.room.state = new RoomEventFilter(); - } - - filterBody.room.state.lazyLoadMembers = true; - } else { - if (filterBody.room != null - && filterBody.room.state != null) { - filterBody.room.state.lazyLoadMembers = null; - - if (!filterBody.room.state.hasData()) { - filterBody.room.state = null; - } - - if (!filterBody.room.hasData()) { - filterBody.room = null; - } - } - } - } - - /** - * Create a RoomEventFilter - * - * @param withLazyLoading true when lazy loading is enabled - * @return a RoomEventFilter or null if lazy loading if OFF - */ - @Nullable - public static RoomEventFilter createRoomEventFilter(boolean withLazyLoading) { - RoomEventFilter roomEventFilter = null; - - if (withLazyLoading) { - roomEventFilter = new RoomEventFilter(); - roomEventFilter.lazyLoadMembers = true; - } - - return roomEventFilter; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/ImageUtils.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/ImageUtils.java deleted file mode 100644 index c5e881e8..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/ImageUtils.java +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.util; - -import android.content.Context; -import android.database.Cursor; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.media.ExifInterface; -import android.net.Uri; -import android.provider.MediaStore; -import android.text.TextUtils; - -import im.vector.matrix.android.internal.legacy.db.MXMediasCache; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; - -public class ImageUtils { - private static final String LOG_TAG = ImageUtils.class.getSimpleName(); - - /** - * Gets the bitmap rotation angle from the {@link android.media.ExifInterface}. - * - * @param context Application context for the content resolver. - * @param uri The URI to find the orientation for. Must be local. - * @return The orientation value, which may be {@link android.media.ExifInterface#ORIENTATION_UNDEFINED}. - */ - public static int getRotationAngleForBitmap(Context context, Uri uri) { - int orientation = getOrientationForBitmap(context, uri); - - int rotationAngle = 0; - - if (ExifInterface.ORIENTATION_ROTATE_90 == orientation) { - rotationAngle = 90; - } else if (ExifInterface.ORIENTATION_ROTATE_180 == orientation) { - rotationAngle = 180; - } else if (ExifInterface.ORIENTATION_ROTATE_270 == orientation) { - rotationAngle = 270; - } - - return rotationAngle; - } - - /** - * Gets the {@link ExifInterface} value for the orientation for this local bitmap Uri. - * - * @param context Application context for the content resolver. - * @param uri The URI to find the orientation for. Must be local. - * @return The orientation value, which may be {@link ExifInterface#ORIENTATION_UNDEFINED}. - */ - public static int getOrientationForBitmap(Context context, Uri uri) { - int orientation = ExifInterface.ORIENTATION_UNDEFINED; - - if (uri == null) { - return orientation; - } - - if (TextUtils.equals(uri.getScheme(), "content")) { - String[] proj = {MediaStore.Images.Media.DATA}; - Cursor cursor = null; - try { - cursor = context.getContentResolver().query(uri, proj, null, null, null); - if (cursor != null && cursor.getCount() > 0) { - cursor.moveToFirst(); - int idxData = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); - String path = cursor.getString(idxData); - if (TextUtils.isEmpty(path)) { - Log.w(LOG_TAG, "Cannot find path in media db for uri " + uri); - return orientation; - } - ExifInterface exif = new ExifInterface(path); - orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED); - } - } catch (Exception e) { - // eg SecurityException from com.google.android.apps.photos.content.GooglePhotosImageProvider URIs - // eg IOException from trying to parse the returned path as a file when it is an http uri. - Log.e(LOG_TAG, "Cannot get orientation for bitmap: " + e.getMessage(), e); - } finally { - if (cursor != null) { - cursor.close(); - } - } - } else if (TextUtils.equals(uri.getScheme(), "file")) { - try { - ExifInterface exif = new ExifInterface(uri.getPath()); - orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED); - } catch (Exception e) { - Log.e(LOG_TAG, "Cannot get EXIF for file uri " + uri + " because " + e.getMessage(), e); - } - } - - return orientation; - } - - public static BitmapFactory.Options decodeBitmapDimensions(InputStream stream) { - BitmapFactory.Options o = new BitmapFactory.Options(); - o.inJustDecodeBounds = true; - BitmapFactory.decodeStream(stream, null, o); - if (o.outHeight == -1 || o.outWidth == -1) { - // this doesn't look like an image... - Log.e(LOG_TAG, "Cannot resize input stream, failed to get w/h."); - return null; - } - return o; - } - - public static int getSampleSize(int w, int h, int maxSize) { - int highestDimensionSize = (h > w) ? h : w; - double ratio = (highestDimensionSize > maxSize) ? (highestDimensionSize / maxSize) : 1.0; - int sampleSize = Integer.highestOneBit((int) Math.floor(ratio)); - if (sampleSize == 0) { - sampleSize = 1; - } - return sampleSize; - } - - /** - * Resize an image from its stream. - * - * @param fullImageStream the image stream - * @param maxSize the square side to draw the image in. -1 to ignore. - * @param aSampleSize the image dimension divider. - * @param quality the image quality (0 -> 100) - * @return a stream of the resized imaged - * @throws IOException file IO exception. - */ - public static InputStream resizeImage(InputStream fullImageStream, int maxSize, int aSampleSize, int quality) throws IOException { - /* - * This is all a bit of a mess because android doesn't ship with sensible bitmap streaming libraries. - * - * General structure here is: (N = size of file, M = decompressed size) - * - Copy inputstream to outstream (Usage: 2N) - * - Release inputstream (Usage: N) - * - Copy outstream to instream (Usage: 2N) --- This is done to make sure we can .reset() the stream else we would potentially - * have to re-download the file once we knew the dimensions of the image (!!!) - * - Release outstream (Usage: N) - * - Decode image dimensions, if the size is good, just return instream, else: - * - Decode the full image with the new sample size (Usage: N + M) - * - Release instream (Usage: M) - * - Bitmap compress to JPEG output stream (Usage: N + M) - * - Release bitmap (Usage: N) - * - Return input stream of output stream (Usage: N) - * Usages assume immediate GC, which is no guarantee. If it didn't, the total usage is 5N + M. In an extreme scenario - * of a full 8 MP image roughly 1.85MB file (3264x2448), this equates to roughly 25 MB of memory. On average, it will - * maybe not immediately release the streams but will probably in the future, so maybe 3N which is ~5.55MB - either - * way this isn't cool. - */ - - ByteArrayOutputStream outstream = new ByteArrayOutputStream(); - - // copy the bytes we just got to the byte array output stream so we can resize.... - byte[] buffer = new byte[2048]; - int l; - while ((l = fullImageStream.read(buffer)) != -1) { - outstream.write(buffer, 0, l); - } - - // we're done with the input stream now so get rid of it (bearing in mind this could be several MB..) - fullImageStream.close(); - - // get the width/height of the image without decoding ALL THE THINGS (though this still makes a copy of the compressed image :/) - ByteArrayInputStream bais = new ByteArrayInputStream(outstream.toByteArray()); - - // allow it to GC.. - outstream.close(); - - BitmapFactory.Options o = decodeBitmapDimensions(bais); - if (o == null) { - return null; - } - int w = o.outWidth; - int h = o.outHeight; - bais.reset(); // yay no need to re-read the stream (which is why we dumped to another stream) - int sampleSize = (maxSize == -1) ? aSampleSize : getSampleSize(w, h, maxSize); - - if (sampleSize == 1) { - // small optimisation - return bais; - } else { - // yucky, we have to decompress the entire (albeit subsampled) bitmap into memory then dump it back into a stream - o = new BitmapFactory.Options(); - o.inSampleSize = sampleSize; - Bitmap bitmap = BitmapFactory.decodeStream(bais, null, o); - if (bitmap == null) { - return null; - } - - bais.close(); - - // recopy it back into an input stream :/ - outstream = new ByteArrayOutputStream(); - bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outstream); - - // cleanup - bitmap.recycle(); - - return new ByteArrayInputStream(outstream.toByteArray()); - } - } - - /** - * Apply rotation to the cached image (stored at imageURL). - * The rotated image replaces the genuine one. - * - * @param context the application - * @param imageURL the genuine image URL. - * @param rotationAngle angle in degrees - * @param mediasCache the used media cache - * @return the rotated bitmap - */ - public static Bitmap rotateImage(Context context, String imageURL, int rotationAngle, MXMediasCache mediasCache) { - Bitmap rotatedBitmap = null; - - try { - Uri imageUri = Uri.parse(imageURL); - - // there is one - if (0 != rotationAngle) { - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inPreferredConfig = Bitmap.Config.ARGB_8888; - options.outWidth = -1; - options.outHeight = -1; - - // decode the bitmap - Bitmap bitmap = null; - try { - final String filename = imageUri.getPath(); - FileInputStream imageStream = new FileInputStream(new File(filename)); - bitmap = BitmapFactory.decodeStream(imageStream, null, options); - imageStream.close(); - } catch (OutOfMemoryError e) { - Log.e(LOG_TAG, "applyExifRotation BitmapFactory.decodeStream : " + e.getMessage(), e); - } catch (Exception e) { - Log.e(LOG_TAG, "applyExifRotation " + e.getMessage(), e); - } - - android.graphics.Matrix bitmapMatrix = new android.graphics.Matrix(); - bitmapMatrix.postRotate(rotationAngle); - Bitmap transformedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), bitmapMatrix, false); - - // Bitmap.createBitmap() can return the same bitmap, so do not recycle it if it is the case - if (transformedBitmap != bitmap) { - bitmap.recycle(); - } - - if (null != mediasCache) { - mediasCache.saveBitmap(transformedBitmap, imageURL); - } - - rotatedBitmap = transformedBitmap; - } - - } catch (OutOfMemoryError e) { - Log.e(LOG_TAG, "applyExifRotation " + e.getMessage(), e); - } catch (Exception e) { - Log.e(LOG_TAG, "applyExifRotation " + e.getMessage(), e); - } - - return rotatedBitmap; - } - - /** - * Apply exif rotation to the cached image (stored at imageURL). - * The rotated image replaces the genuine one. - * - * @param context the application - * @param imageURL the genuine image URL. - * @param mediasCache the used media cache - * @return the rotated bitmap if the operation succeeds. - */ - public static Bitmap applyExifRotation(Context context, String imageURL, MXMediasCache mediasCache) { - Bitmap rotatedBitmap = null; - - try { - Uri imageUri = Uri.parse(imageURL); - // get the exif rotation angle - final int rotationAngle = ImageUtils.getRotationAngleForBitmap(context, imageUri); - - if (0 != rotationAngle) { - rotatedBitmap = rotateImage(context, imageURL, rotationAngle, mediasCache); - } - - } catch (Exception e) { - Log.e(LOG_TAG, "applyExifRotation " + e.getMessage(), e); - } - - return rotatedBitmap; - } - - /** - * Scale and apply exif rotation to an image defines by its stream. - * - * @param context the context - * @param stream the image stream - * @param mimeType the mime type - * @param maxSide reduce the image to this square side. - * @param rotationAngle the rotation angle - * @param mediasCache the media cache. - * @return the media url - */ - public static String scaleAndRotateImage(Context context, InputStream stream, String mimeType, int maxSide, int rotationAngle, MXMediasCache mediasCache) { - String url = null; - - // sanity checks - if ((null != context) && (null != stream) && (null != mediasCache)) { - try { - InputStream scaledStream = ImageUtils.resizeImage(stream, maxSide, 0, 75); - url = mediasCache.saveMedia(scaledStream, null, mimeType); - rotateImage(context, url, rotationAngle, mediasCache); - } catch (Exception e) { - Log.e(LOG_TAG, "rotateAndScale " + e.getMessage(), e); - } - } - return url; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/JsonUtils.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/JsonUtils.java deleted file mode 100644 index 70c02547..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/JsonUtils.java +++ /dev/null @@ -1,674 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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.matrix.android.internal.legacy.util; - -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Modifier; -import java.util.Map; -import java.util.TreeSet; - -import im.vector.matrix.android.internal.legacy.rest.json.BooleanDeserializer; -import im.vector.matrix.android.internal.legacy.rest.json.ConditionDeserializer; -import im.vector.matrix.android.internal.legacy.rest.json.MatrixFieldNamingStrategy; -import im.vector.matrix.android.internal.legacy.rest.model.ContentResponse; -import im.vector.matrix.android.internal.legacy.rest.model.Event; -import im.vector.matrix.android.internal.legacy.rest.model.EventContent; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.legacy.rest.model.PowerLevels; -import im.vector.matrix.android.internal.legacy.rest.model.RoomCreateContent; -import im.vector.matrix.android.internal.legacy.rest.model.RoomMember; -import im.vector.matrix.android.internal.legacy.rest.model.RoomPinnedEventsContent; -import im.vector.matrix.android.internal.legacy.rest.model.RoomTags; -import im.vector.matrix.android.internal.legacy.rest.model.RoomTombstoneContent; -import im.vector.matrix.android.internal.legacy.rest.model.StateEvent; -import im.vector.matrix.android.internal.legacy.rest.model.User; -import im.vector.matrix.android.internal.legacy.rest.model.bingrules.Condition; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.EncryptedEventContent; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.ForwardedRoomKeyContent; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.OlmEventContent; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.OlmPayloadContent; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.RoomKeyContent; -import im.vector.matrix.android.internal.legacy.rest.model.crypto.RoomKeyRequest; -import im.vector.matrix.android.internal.legacy.rest.model.login.RegistrationFlowResponse; -import im.vector.matrix.android.internal.legacy.rest.model.message.AudioMessage; -import im.vector.matrix.android.internal.legacy.rest.model.message.FileMessage; -import im.vector.matrix.android.internal.legacy.rest.model.message.ImageMessage; -import im.vector.matrix.android.internal.legacy.rest.model.message.LocationMessage; -import im.vector.matrix.android.internal.legacy.rest.model.message.Message; -import im.vector.matrix.android.internal.legacy.rest.model.message.StickerJsonMessage; -import im.vector.matrix.android.internal.legacy.rest.model.message.StickerMessage; -import im.vector.matrix.android.internal.legacy.rest.model.message.VideoMessage; -import im.vector.matrix.android.internal.legacy.rest.model.pid.RoomThirdPartyInvite; - -/** - * Static methods for converting json into objects. - */ -public class JsonUtils { - private static final String LOG_TAG = JsonUtils.class.getSimpleName(); - - private static final Gson gson = new GsonBuilder() - .setFieldNamingStrategy(new MatrixFieldNamingStrategy()) - .excludeFieldsWithModifiers(Modifier.PRIVATE, Modifier.STATIC) - .registerTypeAdapter(Condition.class, new ConditionDeserializer()) - .registerTypeAdapter(boolean.class, new BooleanDeserializer(false)) - .registerTypeAdapter(Boolean.class, new BooleanDeserializer(true)) - .create(); - - // add a call to serializeNulls(). - // by default the null parameters are not sent in the requests. - // serializeNulls forces to add them. - private static final Gson gsonWithNullSerialization = new GsonBuilder() - .setFieldNamingStrategy(new MatrixFieldNamingStrategy()) - .excludeFieldsWithModifiers(Modifier.PRIVATE, Modifier.STATIC) - .serializeNulls() - .registerTypeAdapter(Condition.class, new ConditionDeserializer()) - .registerTypeAdapter(boolean.class, new BooleanDeserializer(false)) - .registerTypeAdapter(Boolean.class, new BooleanDeserializer(true)) - .create(); - - // for crypto (canonicalize) - // avoid converting "=" to \u003d - private static final Gson gsonWithoutHtmlEscaping = new GsonBuilder() - .setFieldNamingStrategy(new MatrixFieldNamingStrategy()) - .disableHtmlEscaping() - .excludeFieldsWithModifiers(Modifier.PRIVATE, Modifier.STATIC) - .registerTypeAdapter(Condition.class, new ConditionDeserializer()) - .registerTypeAdapter(boolean.class, new BooleanDeserializer(false)) - .registerTypeAdapter(Boolean.class, new BooleanDeserializer(true)) - .create(); - - /** - * Provides the JSON parser. - * - * @param withNullSerialization true to serialise the null parameters - * @return the JSON parser - */ - public static Gson getGson(boolean withNullSerialization) { - return withNullSerialization ? gsonWithNullSerialization : gson; - } - - /** - * Convert a JSON object to a state event. - * The result is never null. - * - * @param jsonObject the json to convert - * @return a room state - */ - public static StateEvent toStateEvent(JsonElement jsonObject) { - return toClass(jsonObject, StateEvent.class); - } - - /** - * Convert a JSON object to an User. - * The result is never null. - * - * @param jsonObject the json to convert - * @return an user - */ - public static User toUser(JsonElement jsonObject) { - return toClass(jsonObject, User.class); - } - - /** - * Convert a JSON object to a RoomMember. - * The result is never null. - * - * @param jsonObject the json to convert - * @return a RoomMember - */ - public static RoomMember toRoomMember(JsonElement jsonObject) { - return toClass(jsonObject, RoomMember.class); - } - - /** - * Convert a JSON object to a RoomTags. - * The result is never null. - * - * @param jsonObject the json to convert - * @return a RoomTags - */ - public static RoomTags toRoomTags(JsonElement jsonObject) { - return toClass(jsonObject, RoomTags.class); - } - - /** - * Convert a JSON object to a MatrixError. - * The result is never null. - * - * @param jsonObject the json to convert - * @return a MatrixError - */ - public static MatrixError toMatrixError(JsonElement jsonObject) { - return toClass(jsonObject, MatrixError.class); - } - - /** - * Retrieves the message type from a Json object. - * - * @param jsonObject the json object - * @return the message type - */ - @Nullable - public static String getMessageMsgType(JsonElement jsonObject) { - try { - Message message = gson.fromJson(jsonObject, Message.class); - return message.msgtype; - } catch (Exception e) { - Log.e(LOG_TAG, "## getMessageMsgType failed " + e.getMessage(), e); - } - - return null; - } - - /** - * Convert a JSON object to a Message. - * The result is never null. - * - * @param jsonObject the json to convert - * @return a Message - */ - @NonNull - public static Message toMessage(JsonElement jsonObject) { - try { - Message message = gson.fromJson(jsonObject, Message.class); - - // Try to return the right subclass - if (Message.MSGTYPE_IMAGE.equals(message.msgtype)) { - return toImageMessage(jsonObject); - } - - if (Message.MSGTYPE_VIDEO.equals(message.msgtype)) { - return toVideoMessage(jsonObject); - } - - if (Message.MSGTYPE_LOCATION.equals(message.msgtype)) { - return toLocationMessage(jsonObject); - } - - // Try to return the right subclass - if (Message.MSGTYPE_FILE.equals(message.msgtype)) { - return toFileMessage(jsonObject); - } - - if (Message.MSGTYPE_AUDIO.equals(message.msgtype)) { - return toAudioMessage(jsonObject); - } - - // Fall back to the generic Message type - return message; - } catch (Exception e) { - Log.e(LOG_TAG, "## toMessage failed " + e.getMessage(), e); - } - - return new Message(); - } - - /** - * Convert a JSON object to an Event. - * The result is never null. - * - * @param jsonObject the json to convert - * @return an Event - */ - public static Event toEvent(JsonElement jsonObject) { - return toClass(jsonObject, Event.class); - } - - /** - * Convert a JSON object to an EncryptedEventContent. - * The result is never null. - * - * @param jsonObject the json to convert - * @return an EncryptedEventContent - */ - public static EncryptedEventContent toEncryptedEventContent(JsonElement jsonObject) { - return toClass(jsonObject, EncryptedEventContent.class); - } - - /** - * Convert a JSON object to an OlmEventContent. - * The result is never null. - * - * @param jsonObject the json to convert - * @return an OlmEventContent - */ - public static OlmEventContent toOlmEventContent(JsonElement jsonObject) { - return toClass(jsonObject, OlmEventContent.class); - } - - /** - * Convert a JSON object to an OlmPayloadContent. - * The result is never null. - * - * @param jsonObject the json to convert - * @return an OlmPayloadContent - */ - public static OlmPayloadContent toOlmPayloadContent(JsonElement jsonObject) { - return toClass(jsonObject, OlmPayloadContent.class); - } - - /** - * Convert a JSON object to an EventContent. - * The result is never null. - * - * @param jsonObject the json to convert - * @return an EventContent - */ - public static EventContent toEventContent(JsonElement jsonObject) { - return toClass(jsonObject, EventContent.class); - } - - /** - * Convert a JSON object to an RoomKeyContent. - * The result is never null. - * - * @param jsonObject the json to convert - * @return an RoomKeyContent - */ - public static RoomKeyContent toRoomKeyContent(JsonElement jsonObject) { - return toClass(jsonObject, RoomKeyContent.class); - } - - /** - * Convert a JSON object to an RoomKeyRequest. - * The result is never null. - * - * @param jsonObject the json to convert - * @return an RoomKeyRequest - */ - public static RoomKeyRequest toRoomKeyRequest(JsonElement jsonObject) { - return toClass(jsonObject, RoomKeyRequest.class); - } - - /** - * Convert a JSON object to an ForwardedRoomKeyContent. - * The result is never null. - * - * @param jsonObject the json to convert - * @return an ForwardedRoomKeyContent - */ - public static ForwardedRoomKeyContent toForwardedRoomKeyContent(JsonElement jsonObject) { - return toClass(jsonObject, ForwardedRoomKeyContent.class); - } - - /** - * Convert a JSON object to an ImageMessage. - * The result is never null. - * - * @param jsonObject the json to convert - * @return an ImageMessage - */ - public static ImageMessage toImageMessage(JsonElement jsonObject) { - return toClass(jsonObject, ImageMessage.class); - } - - /** - * Convert a JSON object to a StickerMessage. - * The result is never null. - * - * @param jsonObject the json to convert - * @return a StickerMessage - */ - public static StickerMessage toStickerMessage(JsonElement jsonObject) { - final StickerJsonMessage stickerJsonMessage = toClass(jsonObject, StickerJsonMessage.class); - return new StickerMessage(stickerJsonMessage); - } - - /** - * Convert a JSON object to an FileMessage. - * The result is never null. - * - * @param jsonObject the json to convert - * @return an FileMessage - */ - public static FileMessage toFileMessage(JsonElement jsonObject) { - return toClass(jsonObject, FileMessage.class); - } - - /** - * Convert a JSON object to an AudioMessage. - * The result is never null. - * - * @param jsonObject the json to convert - * @return an AudioMessage - */ - public static AudioMessage toAudioMessage(JsonElement jsonObject) { - return toClass(jsonObject, AudioMessage.class); - } - - /** - * Convert a JSON object to a VideoMessage. - * The result is never null. - * - * @param jsonObject the json to convert - * @return a VideoMessage - */ - public static VideoMessage toVideoMessage(JsonElement jsonObject) { - return toClass(jsonObject, VideoMessage.class); - } - - /** - * Convert a JSON object to a LocationMessage. - * The result is never null. - * - * @param jsonObject the json to convert - * @return a LocationMessage - */ - public static LocationMessage toLocationMessage(JsonElement jsonObject) { - return toClass(jsonObject, LocationMessage.class); - } - - /** - * Convert a JSON object to a ContentResponse. - * The result is never null. - * - * @param jsonString the json as string to convert - * @return a ContentResponse - */ - public static ContentResponse toContentResponse(String jsonString) { - return toClass(jsonString, ContentResponse.class); - } - - /** - * Convert a JSON object to a PowerLevels. - * The result is never null. - * - * @param jsonObject the json to convert - * @return a PowerLevels - */ - public static PowerLevels toPowerLevels(JsonElement jsonObject) { - return toClass(jsonObject, PowerLevels.class); - } - - /** - * Convert a JSON object to a RoomThirdPartyInvite. - * The result is never null. - * - * @param jsonObject the json to convert - * @return a RoomThirdPartyInvite - */ - public static RoomThirdPartyInvite toRoomThirdPartyInvite(JsonElement jsonObject) { - return toClass(jsonObject, RoomThirdPartyInvite.class); - } - - /** - * Convert a stringified JSON object to a RegistrationFlowResponse. - * The result is never null. - * - * @param jsonString the json as string to convert - * @return a RegistrationFlowResponse - */ - public static RegistrationFlowResponse toRegistrationFlowResponse(String jsonString) { - return toClass(jsonString, RegistrationFlowResponse.class); - } - - /** - * Convert a JSON object to a RoomTombstoneContent. - * The result is never null. - * - * @param jsonElement the json to convert - * @return a RoomTombstoneContent - */ - public static RoomTombstoneContent toRoomTombstoneContent(final JsonElement jsonElement) { - return toClass(jsonElement, RoomTombstoneContent.class); - } - - /** - * Convert a JSON object to a RoomCreateContent. - * The result is never null. - * - * @param jsonElement the json to convert - * @return a RoomCreateContent - */ - public static RoomCreateContent toRoomCreateContent(final JsonElement jsonElement) { - return toClass(jsonElement, RoomCreateContent.class); - } - - /** - * Convert a JSON object to a RoomPinnedEventsContent. - * The result is never null. - * - * @param jsonElement the json to convert - * @return a RoomPinnedEventsContent - */ - public static RoomPinnedEventsContent toRoomPinnedEventsContent(final JsonElement jsonElement) { - return toClass(jsonElement, RoomPinnedEventsContent.class); - } - - /** - * Convert a JSON object into a class instance. - * The returned value cannot be null. - * - * @param jsonObject the json object to convert - * @param aClass the class - * @return the converted object - */ - public static T toClass(JsonElement jsonObject, Class aClass) { - T object = null; - try { - object = gson.fromJson(jsonObject, aClass); - } catch (Exception e) { - Log.e(LOG_TAG, "## toClass failed " + e.getMessage(), e); - } - if (null == object) { - try { - final Constructor constructor = aClass.getConstructor(); - object = constructor.newInstance(); - } catch (Throwable t) { - Log.e(LOG_TAG, "## toClass failed " + t.getMessage(), t); - } - } - return object; - } - - /** - * Convert a stringified JSON into a class instance. - * The returned value cannot be null. - * - * @param jsonObjectAsString the json object as string to convert - * @param aClass the class - * @return the converted object - */ - public static T toClass(String jsonObjectAsString, Class aClass) { - T object = null; - try { - object = gson.fromJson(jsonObjectAsString, aClass); - } catch (Exception e) { - Log.e(LOG_TAG, "## toClass failed " + e.getMessage(), e); - } - if (null == object) { - try { - final Constructor constructor = aClass.getConstructor(); - object = constructor.newInstance(); - } catch (Throwable t) { - Log.e(LOG_TAG, "## toClass failed " + t.getMessage(), t); - } - } - return object; - } - - /** - * Convert an Event instance to a Json object. - * - * @param event the event instance. - * @return the json object - */ - public static JsonObject toJson(Event event) { - try { - return (JsonObject) gson.toJsonTree(event); - } catch (Exception e) { - Log.e(LOG_TAG, "## toJson failed " + e.getMessage(), e); - } - - return new JsonObject(); - } - - public static JsonObject toJson(Map data) { - try { - return (JsonObject) gson.toJsonTree(data); - } catch (Exception e) { - Log.e(LOG_TAG, "## toJson failed " + e.getMessage(), e); - } - - return new JsonObject(); - } - - /** - * Convert an Message instance into a Json object. - * - * @param message the Message instance. - * @return the json object - */ - public static JsonObject toJson(Message message) { - try { - return (JsonObject) gson.toJsonTree(message); - } catch (Exception e) { - Log.e(LOG_TAG, "## toJson failed " + e.getMessage(), e); - } - - return null; - } - - /** - * Create a canonicalized json string for an object - * - * @param object the object to convert - * @return the canonicalized string - */ - public static String getCanonicalizedJsonString(Object object) { - String canonicalizedJsonString = null; - - if (null != object) { - if (object instanceof JsonElement) { - canonicalizedJsonString = gsonWithoutHtmlEscaping.toJson(canonicalize((JsonElement) object)); - } else { - canonicalizedJsonString = gsonWithoutHtmlEscaping.toJson(canonicalize(gsonWithoutHtmlEscaping.toJsonTree(object))); - } - - if (null != canonicalizedJsonString) { - canonicalizedJsonString = canonicalizedJsonString.replace("\\/", "/"); - } - } - - return canonicalizedJsonString; - } - - /** - * Canonicalize a JsonElement element - * - * @param src the src - * @return the canonicalize element - */ - public static JsonElement canonicalize(JsonElement src) { - // sanity check - if (null == src) { - return null; - } - - if (src instanceof JsonArray) { - // Canonicalize each element of the array - JsonArray srcArray = (JsonArray) src; - JsonArray result = new JsonArray(); - for (int i = 0; i < srcArray.size(); i++) { - result.add(canonicalize(srcArray.get(i))); - } - return result; - } else if (src instanceof JsonObject) { - // Sort the attributes by name, and the canonicalize each element of the object - JsonObject srcObject = (JsonObject) src; - JsonObject result = new JsonObject(); - TreeSet attributes = new TreeSet<>(); - - for (Map.Entry entry : srcObject.entrySet()) { - attributes.add(entry.getKey()); - } - for (String attribute : attributes) { - result.add(attribute, canonicalize(srcObject.get(attribute))); - } - return result; - } else { - return src; - } - } - - /** - * Convert a string from an UTF8 String - * - * @param s the string to convert - * @return the utf-16 string - */ - public static String convertFromUTF8(String s) { - String out = s; - - if (null != out) { - try { - byte[] bytes = out.getBytes(); - out = new String(bytes, "UTF-8"); - } catch (Exception e) { - Log.e(LOG_TAG, "## convertFromUTF8() failed " + e.getMessage(), e); - } - } - - return out; - } - - /** - * Convert a string to an UTF8 String - * - * @param s the string to convert - * @return the utf-8 string - */ - public static String convertToUTF8(String s) { - String out = s; - - if (null != out) { - try { - byte[] bytes = out.getBytes("UTF-8"); - out = new String(bytes); - } catch (Exception e) { - Log.e(LOG_TAG, "## convertToUTF8() failed " + e.getMessage(), e); - } - } - - return out; - } - - /** - * Returns a dedicated parameter as a string - * - * @param paramName the parameter name - * @return the string value, or null if not defined or not a String - */ - @Nullable - public static String getAsString(Map map, String paramName) { - if (map.containsKey(paramName) && map.get(paramName) instanceof String) { - return (String) map.get(paramName); - } - - return null; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/Log.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/Log.java deleted file mode 100644 index 7b738885..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/Log.java +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright 2017 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.util; - -import android.text.TextUtils; - -import java.io.File; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.List; -import java.util.Locale; -import java.util.TimeZone; -import java.util.logging.FileHandler; -import java.util.logging.Formatter; -import java.util.logging.Level; -import java.util.logging.LogRecord; -import java.util.logging.Logger; - -import im.vector.matrix.android.BuildConfig; - -/** - * Intended to mimic {@link android.util.Log} in terms of interface, but with a lot of extra behind the scenes stuff. - */ -public class Log { - private static final String LOG_TAG = "Log"; - - private static final String LINE_SEPARATOR = System.getProperty("line.separator"); - private static final int LOG_SIZE_BYTES = 50 * 1024 * 1024; // 50MB - - // relatively large rotation count because closing > opening the app rotates the log (!) - private static final int LOG_ROTATION_COUNT = 15; - - private static final Logger sLogger = Logger.getLogger("org.matrix.androidsdk"); - private static FileHandler sFileHandler = null; - private static File sCacheDirectory = null; - private static String sFileName = "matrix"; - - // determine if messsages with DEBUG level should be logged or not - public static boolean sShouldLogDebug = BuildConfig.DEBUG; - - public enum EventTag { - /** - * A navigation event, e.g. onPause - */ - NAVIGATION, - /** - * A user triggered event, e.g. onClick - */ - USER, - /** - * User-visible notifications - */ - NOTICE, - /** - * A background event e.g. incoming messages - */ - BACKGROUND - } - - /** - * Initialises the logger. Should be called AFTER {@link Log#setLogDirectory(File)}. - * - * @param fileName the base file name - */ - public static void init(String fileName) { - try { - if (!TextUtils.isEmpty(fileName)) { - sFileName = fileName; - } - sFileHandler = new FileHandler(sCacheDirectory.getAbsolutePath() + "/" + sFileName + ".%g.txt", LOG_SIZE_BYTES, LOG_ROTATION_COUNT); - sFileHandler.setFormatter(new LogFormatter()); - sLogger.setUseParentHandlers(false); - sLogger.setLevel(Level.ALL); - sLogger.addHandler(sFileHandler); - } catch (IOException e) { - } - } - - /** - * Set the directory to put log files. - * - * @param cacheDir The directory, usually {@link android.content.ContextWrapper#getCacheDir()} - */ - public static void setLogDirectory(File cacheDir) { - if (!cacheDir.exists()) { - cacheDir.mkdirs(); - } - sCacheDirectory = cacheDir; - } - - /** - * Set the directory to put log files. - * - * @return the cache directory - */ - public static File getLogDirectory() { - return sCacheDirectory; - } - - /** - * Adds our own log files to the provided list of files. - * - * @param files The list of files to add to. - * @return The same list with more files added. - */ - public static List addLogFiles(List files) { - try { - // reported by GA - if (null != sFileHandler) { - sFileHandler.flush(); - String absPath = sCacheDirectory.getAbsolutePath(); - - for (int i = 0; i <= LOG_ROTATION_COUNT; i++) { - String filepath = absPath + "/" + sFileName + "." + i + ".txt"; - File file = new File(filepath); - if (file.exists()) { - files.add(file); - } - } - } - } catch (Exception e) { - Log.e(LOG_TAG, "## addLogFiles() failed : " + e.getMessage(), e); - } - return files; - } - - private static void logToFile(String level, String tag, String content) { - if (null == sCacheDirectory) { - return; - } - - StringBuilder b = new StringBuilder(); - b.append(Thread.currentThread().getId()); - b.append(" "); - b.append(level); - b.append("/"); - b.append(tag); - b.append(": "); - b.append(content); - sLogger.info(b.toString()); - } - - /** - * Log an Throwable - * - * @param throwable the throwable to log - */ - private static void logToFile(Throwable throwable) { - if (null == sCacheDirectory || throwable == null) { - return; - } - - - StringWriter errors = new StringWriter(); - throwable.printStackTrace(new PrintWriter(errors)); - - sLogger.info(errors.toString()); - } - - /** - * Log events which can be automatically analysed - * - * @param tag the EventTag - * @param content Content to log - */ - public static void event(EventTag tag, String content) { - android.util.Log.v(tag.name(), content); - logToFile("EVENT", tag.name(), content); - } - - /** - * Log connection information, such as urls hit, incoming data, current connection status. - * - * @param tag Log tag - * @param content Content to log - */ - public static void con(String tag, String content) { - android.util.Log.v(tag, content); - logToFile("CON", tag, content); - } - - public static void v(String tag, String content) { - android.util.Log.v(tag, content); - logToFile("V", tag, content); - } - - public static void v(String tag, String content, Throwable throwable) { - android.util.Log.v(tag, content, throwable); - logToFile("V", tag, content); - logToFile(throwable); - } - - public static void d(String tag, String content) { - if (sShouldLogDebug) { - android.util.Log.d(tag, content); - logToFile("D", tag, content); - } - } - - public static void d(String tag, String content, Throwable throwable) { - if (sShouldLogDebug) { - android.util.Log.d(tag, content, throwable); - logToFile("D", tag, content); - logToFile(throwable); - } - } - - public static void i(String tag, String content) { - android.util.Log.i(tag, content); - logToFile("I", tag, content); - } - - public static void i(String tag, String content, Throwable throwable) { - android.util.Log.i(tag, content, throwable); - logToFile("I", tag, content); - logToFile(throwable); - } - - public static void w(String tag, String content) { - android.util.Log.w(tag, content); - logToFile("W", tag, content); - } - - public static void w(String tag, String content, Throwable throwable) { - android.util.Log.w(tag, content, throwable); - logToFile("W", tag, content); - logToFile(throwable); - } - - public static void e(String tag, String content) { - android.util.Log.e(tag, content); - logToFile("E", tag, content); - } - - public static void e(String tag, String content, Throwable throwable) { - android.util.Log.e(tag, content, throwable); - logToFile("E", tag, content); - logToFile(throwable); - } - - public static void wtf(String tag, String content) { - android.util.Log.wtf(tag, content); - logToFile("WTF", tag, content); - } - - public static void wtf(String tag, Throwable throwable) { - android.util.Log.wtf(tag, throwable); - logToFile("WTF", tag, throwable.getMessage()); - logToFile(throwable); - } - - public static void wtf(String tag, String content, Throwable throwable) { - android.util.Log.wtf(tag, content, throwable); - logToFile("WTF", tag, content); - logToFile(throwable); - } - - public static final class LogFormatter extends Formatter { - private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS", Locale.US); - private static boolean mIsTimeZoneSet = false; - - @Override - public String format(LogRecord r) { - if (!mIsTimeZoneSet) { - DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC")); - mIsTimeZoneSet = true; - } - - Throwable thrown = r.getThrown(); - if (thrown != null) { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - sw.write(r.getMessage()); - sw.write(LINE_SEPARATOR); - thrown.printStackTrace(pw); - pw.flush(); - return sw.toString(); - } else { - StringBuilder b = new StringBuilder(); - String date = DATE_FORMAT.format(new Date(r.getMillis())); - b.append(date); - b.append("Z "); - b.append(r.getMessage()); - b.append(LINE_SEPARATOR); - return b.toString(); - } - } - } -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/MXOsHandler.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/MXOsHandler.java deleted file mode 100644 index bfa101b4..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/MXOsHandler.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2014 OpenMarket 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.matrix.android.internal.legacy.util; - -import android.os.Handler; -import android.os.Looper; - -/** - * Override the os handler to support unitary tests - */ -public class MXOsHandler { - - // the internal handler - private final android.os.Handler mHandler; - - /** - * Listener - */ - public interface IPostListener { - // a post has been done in the thread - void onPost(Looper looper); - } - - // static - public static final IPostListener mPostListener = null; - - /** - * Constructor - * - * @param looper the looper - */ - public MXOsHandler(Looper looper) { - mHandler = new Handler(looper); - } - - /** - * Post a runnable - * - * @param r the runnable - * @return true if the runnable is placed - */ - public boolean post(Runnable r) { - boolean result = mHandler.post(r); - - if (result && (null != mPostListener)) { - mPostListener.onPost(mHandler.getLooper()); - } - - return result; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/PermalinkUtils.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/PermalinkUtils.java deleted file mode 100644 index 5fa63c75..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/PermalinkUtils.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.util; - -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.text.TextUtils; - -import im.vector.matrix.android.internal.legacy.rest.model.Event; - -/** - * Useful methods to deals with Matrix permalink - */ -public class PermalinkUtils { - - private static final String MATRIX_TO_URL_BASE = "https://matrix.to/#/"; - - /** - * Creates a permalink for an event. - * Ex: "https://matrix.to/#/!nbzmcXAqpxBXjAdgoX:matrix.org/$1531497316352799BevdV:matrix.org" - * - * @param event the event - * @return the permalink, or null in case of error - */ - @Nullable - public static String createPermalink(Event event) { - if (event == null) { - return null; - } - - return createPermalink(event.roomId, event.eventId); - } - - /** - * Creates a permalink for an id (can be a user Id, Room Id, etc.). - * Ex: "https://matrix.to/#/@benoit:matrix.org" - * - * @param id the id - * @return the permalink, or null in case of error - */ - @Nullable - public static String createPermalink(String id) { - if (TextUtils.isEmpty(id)) { - return null; - } - - return MATRIX_TO_URL_BASE + escape(id); - } - - /** - * Creates a permalink for an event. If you have an event you can use {@link #createPermalink(Event)} - * Ex: "https://matrix.to/#/!nbzmcXAqpxBXjAdgoX:matrix.org/$1531497316352799BevdV:matrix.org" - * - * @param roomId the id of the room - * @param eventId the id of the event - * @return the permalink - */ - @NonNull - public static String createPermalink(@NonNull String roomId, @NonNull String eventId) { - return MATRIX_TO_URL_BASE + escape(roomId) + "/" + escape(eventId); - } - - /** - * Extract the linked id from the universal link - * - * @param url the universal link, Ex: "https://matrix.to/#/@benoit:matrix.org" - * @return the id from the url, ex: "@benoit:matrix.org", or null if the url is not a permalink - */ - public static String getLinkedId(@Nullable String url) { - boolean isSupported = url != null && url.startsWith(MATRIX_TO_URL_BASE); - - if (isSupported) { - return url.substring(MATRIX_TO_URL_BASE.length()); - } - - return null; - } - - - /** - * Escape '/' in id, because it is used as a separator - * - * @param id the id to escape - * @return the escaped id - */ - private static String escape(String id) { - return id.replaceAll("/", "%2F"); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/PolymorphicRequestBodyConverter.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/PolymorphicRequestBodyConverter.java deleted file mode 100644 index a26c0156..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/PolymorphicRequestBodyConverter.java +++ /dev/null @@ -1,61 +0,0 @@ -package im.vector.matrix.android.internal.legacy.util; - - -import java.io.IOException; -import java.lang.annotation.Annotation; -import java.lang.reflect.Type; -import java.util.LinkedHashMap; -import java.util.Map; - -import okhttp3.RequestBody; -import retrofit2.Converter; -import retrofit2.Retrofit; - -public final class PolymorphicRequestBodyConverter implements Converter { - public static final Factory FACTORY = new Factory() { - @Override public Converter requestBodyConverter( - Type type, - Annotation[] parameterAnnotations, - Annotation[] methodAnnotations, - Retrofit retrofit - ) { - return new PolymorphicRequestBodyConverter<>( - this, parameterAnnotations, methodAnnotations, retrofit - ); - } - }; - - private final Factory skipPast; - private final Annotation[] parameterAnnotations; - private final Annotation[] methodsAnnotations; - private final Retrofit retrofit; - private final Map, Converter> cache = new LinkedHashMap<>(); - - PolymorphicRequestBodyConverter( - Factory skipPast, - Annotation[] parameterAnnotations, - Annotation[] methodsAnnotations, - Retrofit retrofit) { - this.skipPast = skipPast; - this.parameterAnnotations = parameterAnnotations; - this.methodsAnnotations = methodsAnnotations; - this.retrofit = retrofit; - } - - @Override public RequestBody convert(T value) throws IOException { - Class cls = value.getClass(); - Converter requestBodyConverter; - synchronized (cache) { - requestBodyConverter = cache.get(cls); - } - if (requestBodyConverter == null) { - requestBodyConverter = retrofit.nextRequestBodyConverter( - skipPast, cls, parameterAnnotations, methodsAnnotations - ); - synchronized (cache) { - cache.put(cls, requestBodyConverter); - } - } - return requestBodyConverter.convert(value); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/ResourceUtils.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/ResourceUtils.java deleted file mode 100755 index 11f8049f..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/ResourceUtils.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.util; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.net.Uri; -import android.text.TextUtils; -import android.webkit.MimeTypeMap; - -import java.io.InputStream; - -/** - * Static resource utility methods. - */ -public class ResourceUtils { - private static final String LOG_TAG = ResourceUtils.class.getSimpleName(); - - /** - * Mime types - **/ - public static final String MIME_TYPE_JPEG = "image/jpeg"; - public static final String MIME_TYPE_JPG = "image/jpg"; - public static final String MIME_TYPE_IMAGE_ALL = "image/*"; - public static final String MIME_TYPE_ALL_CONTENT = "*/*"; - - - public static class Resource { - public InputStream mContentStream; - public String mMimeType; - - public Resource(InputStream contentStream, String mimeType) { - mContentStream = contentStream; - mMimeType = mimeType; - } - - /** - * Close the content stream. - */ - public void close() { - try { - mMimeType = null; - - if (null != mContentStream) { - mContentStream.close(); - mContentStream = null; - } - } catch (Exception e) { - Log.e(LOG_TAG, "Resource.close failed " + e.getLocalizedMessage(), e); - } - } - - /** - * Tells if the opened resource is a jpeg one. - * - * @return true if the opened resource is a jpeg one. - */ - public boolean isJpegResource() { - return MIME_TYPE_JPEG.equals(mMimeType) || MIME_TYPE_JPG.equals(mMimeType); - } - } - - /** - * Get a resource stream and metadata about it given its URI returned from onActivityResult. - * - * @param context the context. - * @param uri the URI - * @param mimetype the mimetype - * @return a {@link Resource} encapsulating the opened resource stream and associated metadata - * or {@code null} if opening the resource stream failed. - */ - public static Resource openResource(Context context, Uri uri, String mimetype) { - try { - // if the mime type is not provided, try to find it out - if (TextUtils.isEmpty(mimetype)) { - mimetype = context.getContentResolver().getType(uri); - - // try to find the mimetype from the filename - if (null == mimetype) { - String extension = MimeTypeMap.getFileExtensionFromUrl(uri.toString().toLowerCase()); - if (extension != null) { - mimetype = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); - } - } - } - - return new Resource( - context.getContentResolver().openInputStream(uri), - mimetype); - - } catch (Exception e) { - Log.e(LOG_TAG, "Failed to open resource input stream", e); - } - - return null; - } - - /** - * Creates a thumbnail bitmap from a media Uri - * - * @param context the context - * @param mediaUri the media Uri - * @param maxThumbWidth max thumbnail width - * @param maxThumbHeight max thumbnail height - * @return the bitmap. - */ - public static Bitmap createThumbnailBitmap(Context context, Uri mediaUri, int maxThumbWidth, int maxThumbHeight) { - Bitmap thumbnailBitmap = null; - ResourceUtils.Resource resource = ResourceUtils.openResource(context, mediaUri, null); - - // check if the resource can be i - if (null == resource) { - return null; - } - - try { - // need to decompress the high res image - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inPreferredConfig = Bitmap.Config.ARGB_8888; - resource = ResourceUtils.openResource(context, mediaUri, null); - - // get the full size bitmap - Bitmap fullSizeBitmap = null; - - if (null != resource) { - try { - fullSizeBitmap = BitmapFactory.decodeStream(resource.mContentStream, null, options); - } catch (Exception e) { - Log.e(LOG_TAG, "BitmapFactory.decodeStream fails " + e.getLocalizedMessage(), e); - } - } - - // succeeds to retrieve the full size bitmap - if (null != fullSizeBitmap) { - - // the bitmap is smaller that max sizes - if ((fullSizeBitmap.getHeight() < maxThumbHeight) && (fullSizeBitmap.getWidth() < maxThumbWidth)) { - thumbnailBitmap = fullSizeBitmap; - } else { - double thumbnailWidth = maxThumbWidth; - double thumbnailHeight = maxThumbHeight; - - double imageWidth = fullSizeBitmap.getWidth(); - double imageHeight = fullSizeBitmap.getHeight(); - - if (imageWidth > imageHeight) { - thumbnailHeight = thumbnailWidth * imageHeight / imageWidth; - } else { - thumbnailWidth = thumbnailHeight * imageWidth / imageHeight; - } - - try { - thumbnailBitmap = Bitmap.createScaledBitmap((null == fullSizeBitmap) ? thumbnailBitmap : fullSizeBitmap, - (int) thumbnailWidth, (int) thumbnailHeight, false); - } catch (OutOfMemoryError ex) { - Log.e(LOG_TAG, "createThumbnailBitmap " + ex.getMessage(), ex); - } - } - - // reduce the memory consumption - if (null != fullSizeBitmap) { - fullSizeBitmap.recycle(); - System.gc(); - } - } - - if (null != resource) { - resource.mContentStream.close(); - } - - } catch (Exception e) { - Log.e(LOG_TAG, "createThumbnailBitmap fails " + e.getLocalizedMessage()); - } - - return thumbnailBitmap; - } -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/SecretKeyAndVersion.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/SecretKeyAndVersion.java deleted file mode 100644 index 1258ba88..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/SecretKeyAndVersion.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.util; - -import javax.crypto.SecretKey; - -/** - * Tuple which contains the secret key and the version of Android when the key has been generated - */ -public class SecretKeyAndVersion { - // The key - private final SecretKey secretKey; - - // the android version when the key has been generated - private final int androidVersionWhenTheKeyHasBeenGenerated; - - /** - * @param secretKey the key - * @param androidVersionWhenTheKeyHasBeenGenerated the android version when the key has been generated - */ - public SecretKeyAndVersion(SecretKey secretKey, int androidVersionWhenTheKeyHasBeenGenerated) { - this.secretKey = secretKey; - this.androidVersionWhenTheKeyHasBeenGenerated = androidVersionWhenTheKeyHasBeenGenerated; - } - - /** - * Get the key - * - * @return the key - */ - public SecretKey getSecretKey() { - return secretKey; - } - - /** - * Get the android version when the key has been generated - * - * @return the android version when the key has been generated - */ - public int getAndroidVersionWhenTheKeyHasBeenGenerated() { - return androidVersionWhenTheKeyHasBeenGenerated; - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/UnsentEventsManager.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/UnsentEventsManager.java deleted file mode 100644 index d07e44c5..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/UnsentEventsManager.java +++ /dev/null @@ -1,575 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.util; - -import android.content.Context; -import android.text.TextUtils; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.Timer; -import java.util.TimerTask; - -import im.vector.matrix.android.internal.legacy.MXDataHandler; -import im.vector.matrix.android.internal.legacy.listeners.IMXNetworkEventListener; -import im.vector.matrix.android.internal.legacy.network.NetworkConnectivityReceiver; -import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback; -import im.vector.matrix.android.internal.legacy.rest.callback.RestAdapterCallback; -import im.vector.matrix.android.internal.legacy.rest.model.MatrixError; -import im.vector.matrix.android.internal.network.ssl.CertUtil; -import im.vector.matrix.android.internal.network.ssl.UnrecognizedCertificateException; -import retrofit2.Response; - -/** - * unsent matrix events manager - * This manager schedules the unsent events sending. - * 1 - it keeps the unsent events order (i.e. wait that the first event is resent before sending the second one) - * 2 - Apply the retry rules (event time life, 3 tries...) - */ -public class UnsentEventsManager { - - private static final String LOG_TAG = UnsentEventsManager.class.getSimpleName(); - - // 3 minutes - private static final int MAX_MESSAGE_LIFETIME_MS = 180000; - - // perform only MAX_RETRIES retries - private static final int MAX_RETRIES = 4; - - // The jitter value to apply to compute a random retry time. - private static final int RETRY_JITTER_MS = 3000; - - // the network receiver - private final NetworkConnectivityReceiver mNetworkConnectivityReceiver; - // faster way to check if the event is already sent - private final Map mUnsentEventsMap = new HashMap<>(); - // get the sending order - private final List mUnsentEvents = new ArrayList<>(); - // true of the device is connected to a data network - private boolean mbIsConnected = false; - - // matrix error management - private final MXDataHandler mDataHandler; - - /** - * storage class - */ - private class UnsentEventSnapshot { - // first time the message has been sent - // -1 to ignore age test - private long mAge; - // the number of retries - // it should be limited - private int mRetryCount; - // retry callback. - private RestAdapterCallback.RequestRetryCallBack mRequestRetryCallBack; - // retry timer - private Timer mAutoResendTimer = null; - - public Timer mLifeTimeTimer = null; - // the retry is in progress - public boolean mIsResending = false; - // human description of the event - // The snapshot creator can hide some fields - public String mEventDescription = null; - - /** - * - */ - public boolean waitToBeResent() { - return (null != mAutoResendTimer); - } - - /** - * Resend the event after a delay. - * - * @param delayMs the delay in milliseconds. - * @return true if the operation succeeds - */ - public boolean resendEventAfter(int delayMs) { - stopTimer(); - - try { - if (null != mEventDescription) { - Log.d(LOG_TAG, "Resend after " + delayMs + " [" + mEventDescription + "]"); - } - - mAutoResendTimer = new Timer(); - mAutoResendTimer.schedule(new TimerTask() { - @Override - public void run() { - try { - mIsResending = true; - - if (null != mEventDescription) { - Log.d(LOG_TAG, "Resend [" + mEventDescription + "]"); - } - - mRequestRetryCallBack.onRetry(); - } catch (Throwable throwable) { - mIsResending = false; - Log.e(LOG_TAG, "## resendEventAfter() : " + mEventDescription + " + onRetry failed " + throwable.getMessage(), throwable); - } - } - }, delayMs); - return true; - - } catch (Throwable t) { - Log.e(LOG_TAG, "## resendEventAfter failed " + t.getMessage(), t); - } - - return false; - } - - /** - * Stop any pending resending timer. - */ - public void stopTimer() { - if (null != mAutoResendTimer) { - mAutoResendTimer.cancel(); - mAutoResendTimer = null; - } - } - - /** - * Stop timers. - */ - public void stopTimers() { - if (null != mAutoResendTimer) { - mAutoResendTimer.cancel(); - mAutoResendTimer = null; - } - - if (null != mLifeTimeTimer) { - mLifeTimeTimer.cancel(); - mLifeTimeTimer = null; - } - } - } - - /** - * Constructor - * - * @param networkConnectivityReceiver the network received - * @param dataHandler the data handler - */ - public UnsentEventsManager(NetworkConnectivityReceiver networkConnectivityReceiver, MXDataHandler dataHandler) { - mNetworkConnectivityReceiver = networkConnectivityReceiver; - - // add a default listener - // to resend the unsent messages - mNetworkConnectivityReceiver.addEventListener(new IMXNetworkEventListener() { - @Override - public void onNetworkConnectionUpdate(boolean isConnected) { - mbIsConnected = isConnected; - - if (isConnected) { - resentUnsents(); - } - } - }); - - mbIsConnected = mNetworkConnectivityReceiver.isConnected(); - - mDataHandler = dataHandler; - } - - /** - * Warn that the apiCallback has been called - * - * @param apiCallback the called apiCallback - */ - public void onEventSent(ApiCallback apiCallback) { - if (null != apiCallback) { - UnsentEventSnapshot snapshot = null; - - synchronized (mUnsentEventsMap) { - if (mUnsentEventsMap.containsKey(apiCallback)) { - snapshot = mUnsentEventsMap.get(apiCallback); - } - } - - if (null != snapshot) { - if (null != snapshot.mEventDescription) { - Log.d(LOG_TAG, "Resend Succeeded [" + snapshot.mEventDescription + "]"); - } - - snapshot.stopTimers(); - - synchronized (mUnsentEventsMap) { - mUnsentEventsMap.remove(apiCallback); - mUnsentEvents.remove(snapshot); - } - - resentUnsents(); - } - } - } - - /** - * Clear the session data - */ - public void clear() { - synchronized (mUnsentEventsMap) { - for (UnsentEventSnapshot snapshot : mUnsentEvents) { - snapshot.stopTimers(); - } - - mUnsentEvents.clear(); - mUnsentEventsMap.clear(); - } - } - - /** - * @return the network connectivity receiver - */ - public NetworkConnectivityReceiver getNetworkConnectivityReceiver() { - return mNetworkConnectivityReceiver; - } - - /** - * @return the context - */ - public Context getContext() { - return mDataHandler.getStore().getContext(); - } - - /** - * The event failed to be sent and cannot be resent. - * It triggers the error callbacks. - * - * @param eventDescription the event description - * @param exception the exception - * @param callback the callback. - */ - private static void triggerErrorCallback(MXDataHandler dataHandler, String eventDescription, Response response, Exception exception, ApiCallback callback) { - if ((null != exception) && !TextUtils.isEmpty(exception.getMessage())) { - // privacy - //Log.e(LOG_TAG, error.getMessage() + " url=" + error.getUrl()); - Log.e(LOG_TAG, exception.getLocalizedMessage(), exception); - } - - if (null == exception) { - try { - if (null != eventDescription) { - Log.e(LOG_TAG, "Unexpected Error " + eventDescription); - } - if (null != callback) { - callback.onUnexpectedError(null); - } - } catch (Exception e) { - // privacy - //Log.e(LOG_TAG, "Exception UnexpectedError " + e.getMessage() + " while managing " + error.getUrl()); - Log.e(LOG_TAG, "Exception UnexpectedError " + e.getMessage(), e); - } - } else if (exception instanceof IOException) { - try { - if (null != eventDescription) { - Log.e(LOG_TAG, "Network Error " + eventDescription); - } - if (null != callback) { - callback.onNetworkError(exception); - } - } catch (Exception e) { - // privacy - //Log.e(LOG_TAG, "Exception NetworkError " + e.getMessage() + " while managing " + error.getUrl()); - Log.e(LOG_TAG, "Exception NetworkError " + e.getMessage(), e); - } - } else { - // Try to convert this into a Matrix error - MatrixError mxError; - try { - mxError = JsonUtils.getGson(false).fromJson(response.errorBody().string(), MatrixError.class); - } catch (Exception e) { - mxError = null; - } - if (mxError != null) { - try { - if (null != eventDescription) { - Log.e(LOG_TAG, "Matrix Error " + mxError + " " + eventDescription); - } - - if (MatrixError.isConfigurationErrorCode(mxError.errcode)) { - dataHandler.onConfigurationError(mxError.errcode); - } else if (null != callback) { - callback.onMatrixError(mxError); - } - - } catch (Exception e) { - // privacy - //Log.e(LOG_TAG, "Exception MatrixError " + e.getMessage() + " while managing " + error.getUrl()); - Log.e(LOG_TAG, "Exception MatrixError " + e.getLocalizedMessage(), e); - } - } else { - try { - if (null != eventDescription) { - Log.e(LOG_TAG, "Unexpected Error " + eventDescription); - } - - if (null != callback) { - callback.onUnexpectedError(exception); - } - } catch (Exception e) { - // privacy - //Log.e(LOG_TAG, "Exception UnexpectedError " + e.getMessage() + " while managing " + error.getUrl()); - Log.e(LOG_TAG, "Exception UnexpectedError " + e.getLocalizedMessage(), e); - } - } - } - } - - /** - * A request fails with an unknown matrix token error code. - * - * @param matrixErrorCode the matrix error code - * @param eventDescription the event description - */ - public void onConfigurationErrorCode(final String matrixErrorCode, final String eventDescription) { - Log.e(LOG_TAG, eventDescription + " failed because of an unknown matrix token"); - mDataHandler.onConfigurationError(matrixErrorCode); - } - - /** - * warns that an event failed to be sent. - * - * @param eventDescription the event description - * @param ignoreEventTimeLifeInOffline tell if the event timelife is ignored in offline mode - * @param response Retrofit response - * @param exception Retrofit Exception - * @param apiCallback the apiCallback. - * @param requestRetryCallBack requestRetryCallBack. - */ - public void onEventSendingFailed(final String eventDescription, - final boolean ignoreEventTimeLifeInOffline, - final Response response, - final Exception exception, - final ApiCallback apiCallback, - final RestAdapterCallback.RequestRetryCallBack requestRetryCallBack) { - boolean isManaged = false; - - if (null != eventDescription) { - Log.d(LOG_TAG, "Fail to send [" + eventDescription + "]"); - } - - if ((null != requestRetryCallBack) && (null != apiCallback)) { - synchronized (mUnsentEventsMap) { - UnsentEventSnapshot snapshot; - - // Try to convert this into a Matrix error - MatrixError mxError = null; - - if (null != response) { - try { - mxError = JsonUtils.getGson(false).fromJson(response.errorBody().string(), MatrixError.class); - } catch (Exception e) { - mxError = null; - } - } - - // trace the matrix error. - if ((null != eventDescription) && (null != mxError)) { - Log.d(LOG_TAG, "Matrix error " + mxError.errcode + " " + mxError.getMessage() + " [" + eventDescription + "]"); - - if (MatrixError.isConfigurationErrorCode(mxError.errcode)) { - Log.e(LOG_TAG, "## onEventSendingFailed() : invalid token detected"); - mDataHandler.onConfigurationError(mxError.errcode); - triggerErrorCallback(mDataHandler, eventDescription, response, exception, apiCallback); - return; - } - } - - int matrixRetryTimeout = -1; - - if ((null != mxError) && MatrixError.LIMIT_EXCEEDED.equals(mxError.errcode) && (null != mxError.retry_after_ms)) { - matrixRetryTimeout = mxError.retry_after_ms + 200; - } - - if (null != exception) { - UnrecognizedCertificateException unrecCertEx = CertUtil.INSTANCE.getCertificateException(exception); - if (null != unrecCertEx) { - Log.e(LOG_TAG, "## onEventSendingFailed() : SSL issue detected"); - mDataHandler.onSSLCertificateError(unrecCertEx); - triggerErrorCallback(mDataHandler, eventDescription, response, exception, apiCallback); - return; - } - } - - // some matrix errors are not trapped. - if ((null == mxError) || !mxError.isSupportedErrorCode() || MatrixError.LIMIT_EXCEEDED.equals(mxError.errcode)) { - // is it the first time that the event has been sent ? - if (mUnsentEventsMap.containsKey(apiCallback)) { - snapshot = mUnsentEventsMap.get(apiCallback); - - snapshot.mIsResending = false; - snapshot.stopTimer(); - - // assume that LIMIT_EXCEEDED error is not a default retry - if (matrixRetryTimeout < 0) { - snapshot.mRetryCount++; - } - - // any event has a time life to avoid very old messages - long timeLife = 0; - - // age < 0 means that the event time life is ignored - if (snapshot.mAge > 0) { - timeLife = System.currentTimeMillis() - snapshot.mAge; - } - - if ((timeLife > MAX_MESSAGE_LIFETIME_MS) || (snapshot.mRetryCount > MAX_RETRIES)) { - snapshot.stopTimers(); - mUnsentEventsMap.remove(apiCallback); - mUnsentEvents.remove(snapshot); - - if (null != eventDescription) { - Log.d(LOG_TAG, "Cancel [" + eventDescription + "]"); - } - - isManaged = false; - } else { - isManaged = true; - } - } else { - snapshot = new UnsentEventSnapshot(); - - try { - snapshot.mAge = ignoreEventTimeLifeInOffline ? -1 : System.currentTimeMillis(); - snapshot.mRequestRetryCallBack = requestRetryCallBack; - snapshot.mRetryCount = 1; - snapshot.mEventDescription = eventDescription; - mUnsentEventsMap.put(apiCallback, snapshot); - mUnsentEvents.add(snapshot); - - if (mbIsConnected || !ignoreEventTimeLifeInOffline) { - // the event has a life time - final UnsentEventSnapshot fSnapshot = snapshot; - fSnapshot.mLifeTimeTimer = new Timer(); - fSnapshot.mLifeTimeTimer.schedule(new TimerTask() { - @Override - public void run() { - try { - - if (null != eventDescription) { - Log.d(LOG_TAG, "Cancel to send [" + eventDescription + "]"); - } - - fSnapshot.stopTimers(); - synchronized (mUnsentEventsMap) { - mUnsentEventsMap.remove(apiCallback); - mUnsentEvents.remove(fSnapshot); - } - - triggerErrorCallback(mDataHandler, eventDescription, response, exception, apiCallback); - } catch (Exception e) { - Log.e(LOG_TAG, "## onEventSendingFailed() : failure Msg=" + e.getMessage(), e); - } - } - }, MAX_MESSAGE_LIFETIME_MS); - } else if (ignoreEventTimeLifeInOffline) { - Log.d(LOG_TAG, "The request " + eventDescription + " will be sent when a network will be available"); - } - } catch (Throwable throwable) { - Log.e(LOG_TAG, "## snapshot creation failed " + throwable.getMessage(), throwable); - - if (null != snapshot.mLifeTimeTimer) { - snapshot.mLifeTimeTimer.cancel(); - } - - mUnsentEventsMap.remove(apiCallback); - mUnsentEvents.remove(snapshot); - - try { - triggerErrorCallback(mDataHandler, eventDescription, response, exception, apiCallback); - } catch (Exception e) { - Log.e(LOG_TAG, "## onEventSendingFailed() : failure Msg=" + e.getMessage(), e); - } - } - - isManaged = true; - } - - // retry to send the message ? - if (isManaged) { - // resend the event only if there is an available network - // retrofitError.isNetworkError() does not provide a valid description of the failure - // 1- there is no available network / the connection is lost. (what we could expect) - // 2- the server did not response after 15s : the client would wrongly behave, it would wait until to switch to a valid network - // It never happens, so the message is never resent. - // - if (mbIsConnected) { - int jitterTime = ((int) Math.pow(2, snapshot.mRetryCount)) - + (Math.abs(new Random(System.currentTimeMillis()).nextInt()) % RETRY_JITTER_MS); - isManaged = snapshot.resendEventAfter((matrixRetryTimeout > 0) ? matrixRetryTimeout : jitterTime); - } - } - } - } - } - - if (!isManaged) { - Log.d(LOG_TAG, "Cannot resend it"); - triggerErrorCallback(mDataHandler, eventDescription, response, exception, apiCallback); - } - } - - /** - * check if some messages must be resent - */ - private void resentUnsents() { - Log.d(LOG_TAG, "resentUnsents"); - - synchronized (mUnsentEventsMap) { - if (mUnsentEvents.size() > 0) { - List staledSnapShots = new ArrayList<>(); - - // retry the first - for (int index = 0; index < mUnsentEvents.size(); index++) { - UnsentEventSnapshot unsentEventSnapshot = mUnsentEvents.get(index); - - // check if there is no required delay to resend the message - if (!unsentEventSnapshot.waitToBeResent()) { - // if the message is already resending, - if (unsentEventSnapshot.mIsResending) { - // do not resend any other one to try to keep the messages sending order. - } else { - if (null != unsentEventSnapshot.mEventDescription) { - Log.d(LOG_TAG, "Automatically resend " + unsentEventSnapshot.mEventDescription); - } - - try { - unsentEventSnapshot.mIsResending = true; - unsentEventSnapshot.mRequestRetryCallBack.onRetry(); - break; - } catch (Exception e) { - unsentEventSnapshot.mIsResending = false; - staledSnapShots.add(unsentEventSnapshot); - Log.e(LOG_TAG, "## resentUnsents() : " + unsentEventSnapshot.mEventDescription + " onRetry() failed " + e.getMessage(), e); - } - } - } - } - - mUnsentEvents.removeAll(staledSnapShots); - } - } - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/VersionsUtil.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/VersionsUtil.java deleted file mode 100644 index 0b7724fa..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/util/VersionsUtil.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2018 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.matrix.android.internal.legacy.util; - -import android.support.annotation.Nullable; - -import im.vector.matrix.android.internal.legacy.rest.model.Versions; - -/** - * Companion for class {@link Versions} - */ -public class VersionsUtil { - - private static final String FEATURE_LAZY_LOAD_MEMBERS = "m.lazy_load_members"; - - /** - * Return true if the server support the lazy loading of room members - * - * @param versions the Versions object from the server request - * @return true if the server support the lazy loading of room members - */ - public static boolean supportLazyLoadMembers(@Nullable Versions versions) { - return versions != null - && versions.unstableFeatures != null - && versions.unstableFeatures.containsKey(FEATURE_LAZY_LOAD_MEMBERS) - && versions.unstableFeatures.get(FEATURE_LAZY_LOAD_MEMBERS); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/view/AutoScrollDownListView.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/view/AutoScrollDownListView.java deleted file mode 100644 index 5fad5f8a..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/view/AutoScrollDownListView.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * Copyright 2018 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.matrix.android.internal.legacy.view; - -import android.content.Context; -import android.util.AttributeSet; -import android.widget.ListView; - -import im.vector.matrix.android.internal.legacy.util.Log; - -/** - * The listView automatically scrolls down when its height is updated. - * It is used to scroll the list when the keyboard is displayed - * Note that the list scrolls down automatically thank to android:transcriptMode="normal" in the XML - */ -public class AutoScrollDownListView extends ListView { - private static final String LOG_TAG = AutoScrollDownListView.class.getSimpleName(); - - private boolean mLockSelectionOnResize = false; - - public AutoScrollDownListView(Context context) { - super(context); - } - - public AutoScrollDownListView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public AutoScrollDownListView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - @Override - protected void onSizeChanged(int xNew, int yNew, int xOld, int yOld) { - super.onSizeChanged(xNew, yNew, xOld, yOld); - - if (!mLockSelectionOnResize) { - // check if the keyboard is displayed - // we don't want that the list scrolls to the bottom when the keyboard is hidden. - if (yNew < yOld) { - postDelayed(new Runnable() { - @Override - public void run() { - setSelection(getCount() - 1); - } - }, 100); - } - } - } - - /** - * The listview selection is locked even if the view position is updated. - */ - public void lockSelectionOnResize() { - mLockSelectionOnResize = true; - } - - @Override - protected void layoutChildren() { - // the adapter items are added without refreshing the list (back pagination only) - // to reduce the number of refresh - try { - super.layoutChildren(); - } catch (Exception e) { - Log.e(LOG_TAG, "## layoutChildren() failed " + e.getMessage(), e); - } - } - - @Override - // require to avoid lint errors with MatrixMessageListFragment - public void setSelectionFromTop(int position, int y) { - super.setSelectionFromTop(position, y); - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/view/HtmlTagHandler.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/view/HtmlTagHandler.java deleted file mode 100755 index 18d0bec5..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/view/HtmlTagHandler.java +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright (C) 2013-2015 Dominik Schürmann - * Copyright (C) 2013-2015 Juha Kuitunen - * Copyright (C) 2013 Mohammed Lakkadshaw - * Copyright (C) 2007 The Android Open Source Project - * - * 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.matrix.android.internal.legacy.view; - -import android.content.Context; -import android.support.annotation.ColorInt; -import android.support.v4.content.ContextCompat; -import android.text.Editable; -import android.text.Html; -import android.text.Layout; -import android.text.Spannable; -import android.text.Spanned; -import android.text.style.AlignmentSpan; -import android.text.style.BackgroundColorSpan; -import android.text.style.BulletSpan; -import android.text.style.LeadingMarginSpan; -import android.text.style.StrikethroughSpan; -import android.text.style.TypefaceSpan; - -import org.xml.sax.XMLReader; - -import java.util.Stack; - -/** - * Some parts of this code are based on android.text.Html - */ -// custom implementation of org.sufficientlysecure.htmltextview.HtmlTagHandler -// to have the same UI as the webclient -public class HtmlTagHandler implements Html.TagHandler { - /** - * Keeps track of lists (ol, ul). On bottom of Stack is the outermost list - * and on top of Stack is the most nested list - */ - private final Stack lists = new Stack<>(); - /** - * Tracks indexes of ordered lists so that after a nested list ends - * we can continue with correct index of outer list - */ - private final Stack olNextIndex = new Stack<>(); - - /** - * Running HTML table string based off of the root table tag. Root table tag being the tag which - * isn't embedded within any other table tag. Example: - * - * - * ... - *
    - * ... - *
    - * ... - * - * - */ - StringBuilder tableHtmlBuilder = new StringBuilder(); - /** - * Tells us which level of table tag we're on; ultimately used to find the root table tag. - */ - int tableTagLevel = 0; - - private static final int indent = 10; - private static final int listItemIndent = indent * 2; - private static final BulletSpan bullet = new BulletSpan(indent); - - public Context mContext; - - public int mCodeBlockBackgroundColor = -1; - - private static class Ul { - } - - private static class Ol { - } - - private static class Code { - } - - private static class Center { - } - - private static class Strike { - } - - private static class Table { - } - - private static class Tr { - } - - private static class Th { - } - - private static class Td { - } - - /** - * Defines the code block background color - * @param color the new color - */ - public void setCodeBlockBackgroundColor(@ColorInt int color) { - mCodeBlockBackgroundColor = color; - } - - @Override - public void handleTag(final boolean opening, final String tag, Editable output, final XMLReader xmlReader) { - if (opening) { - - if (tag.equalsIgnoreCase("ul")) { - lists.push(tag); - } else if (tag.equalsIgnoreCase("ol")) { - lists.push(tag); - olNextIndex.push(1); - } else if (tag.equalsIgnoreCase("li")) { - if (output.length() > 0 && output.charAt(output.length() - 1) != '\n') { - output.append("\n"); - } - String parentList = lists.peek(); - if (parentList.equalsIgnoreCase("ol")) { - start(output, new Ol()); - output.append(olNextIndex.peek().toString()).append(". "); - olNextIndex.push(olNextIndex.pop() + 1); - } else if (parentList.equalsIgnoreCase("ul")) { - start(output, new Ul()); - } - } else if (tag.equalsIgnoreCase("code")) { - start(output, new Code()); - } else if (tag.equalsIgnoreCase("center")) { - start(output, new Center()); - } else if (tag.equalsIgnoreCase("s") || tag.equalsIgnoreCase("strike")) { - start(output, new Strike()); - } else if (tag.equalsIgnoreCase("table")) { - start(output, new Table()); - if (tableTagLevel == 0) { - tableHtmlBuilder = new StringBuilder(); - // We need some text for the table to be replaced by the span because - // the other tags will remove their text when their text is extracted - output.append("table placeholder"); - } - - tableTagLevel++; - } - else if (tag.equalsIgnoreCase("tr")) { - start(output, new Tr()); - } else if (tag.equalsIgnoreCase("th")) { - start(output, new Th()); - } else if (tag.equalsIgnoreCase("td")) { - start(output, new Td()); - } - } else { - if (tag.equalsIgnoreCase("ul")) { - lists.pop(); - } else if (tag.equalsIgnoreCase("ol")) { - lists.pop(); - olNextIndex.pop(); - } else if (tag.equalsIgnoreCase("li")) { - if (lists.peek().equalsIgnoreCase("ul")) { - if (output.length() > 0 && output.charAt(output.length() - 1) != '\n') { - output.append("\n"); - } - // Nested BulletSpans increases distance between bullet and text, so we must prevent it. - int bulletMargin = indent; - if (lists.size() > 1) { - bulletMargin = indent - bullet.getLeadingMargin(true); - if (lists.size() > 2) { - // This get's more complicated when we add a LeadingMarginSpan into the same line: - // we have also counter it's effect to BulletSpan - bulletMargin -= (lists.size() - 2) * listItemIndent; - } - } - BulletSpan newBullet = new BulletSpan(bulletMargin); - end(output, Ul.class, false, - new LeadingMarginSpan.Standard(listItemIndent * (lists.size() - 1)), - newBullet); - } else if (lists.peek().equalsIgnoreCase("ol")) { - if (output.length() > 0 && output.charAt(output.length() - 1) != '\n') { - output.append("\n"); - } - int numberMargin = listItemIndent * (lists.size() - 1); - if (lists.size() > 2) { - // Same as in ordered lists: counter the effect of nested Spans - numberMargin -= (lists.size() - 2) * listItemIndent; - } - end(output, Ol.class, false, new LeadingMarginSpan.Standard(numberMargin)); - } - } else if (tag.equalsIgnoreCase("code")) { - if (-1 == mCodeBlockBackgroundColor) { - mCodeBlockBackgroundColor = ContextCompat.getColor(mContext, android.R.color.darker_gray); - } - - end(output, Code.class, false, new BackgroundColorSpan(mCodeBlockBackgroundColor), new TypefaceSpan("monospace")); - } else if (tag.equalsIgnoreCase("center")) { - end(output, Center.class, true, new AlignmentSpan.Standard(Layout.Alignment.ALIGN_CENTER)); - } else if (tag.equalsIgnoreCase("s") || tag.equalsIgnoreCase("strike")) { - end(output, Strike.class, false, new StrikethroughSpan()); - } else if (tag.equalsIgnoreCase("table")) { - tableTagLevel--; - - // When we're back at the root-level table - end(output, Table.class, false); - } - else if (tag.equalsIgnoreCase("tr")) { - end(output, Tr.class, false); - } else if (tag.equalsIgnoreCase("th")) { - end(output, Th.class, false); - } else if (tag.equalsIgnoreCase("td")) { - end(output, Td.class, false); - } - } - - storeTableTags(opening, tag); - } - - /** - * If we're arriving at a table tag or are already within a table tag, then we should store it - * the raw HTML for our ClickableTableSpan - */ - private void storeTableTags(boolean opening, String tag) { - if (tableTagLevel > 0 || tag.equalsIgnoreCase("table")) { - tableHtmlBuilder.append("<"); - if (!opening) { - tableHtmlBuilder.append("/"); - } - tableHtmlBuilder - .append(tag.toLowerCase()) - .append(">"); - } - } - - /** - * Mark the opening tag by using private classes - */ - private void start(Editable output, Object mark) { - int len = output.length(); - output.setSpan(mark, len, len, Spannable.SPAN_MARK_MARK); - } - - /** - * Modified from {@link android.text.Html} - */ - private void end(Editable output, Class kind, boolean paragraphStyle, Object... replaces) { - Object obj = getLast(output, kind); - // start of the tag - int where = output.getSpanStart(obj); - // end of the tag - int len = output.length(); - - // If we're in a table, then we need to store the raw HTML for later - if (tableTagLevel > 0) { - final CharSequence extractedSpanText = extractSpanText(output, kind); - tableHtmlBuilder.append(extractedSpanText); - } - - output.removeSpan(obj); - - if (where != len) { - int thisLen = len; - // paragraph styles like AlignmentSpan need to end with a new line! - if (paragraphStyle) { - output.append("\n"); - thisLen++; - } - for (Object replace : replaces) { - output.setSpan(replace, where, thisLen, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - } - } - } - - /** - * Returns the text contained within a span and deletes it from the output string - */ - private CharSequence extractSpanText(Editable output, Class kind) { - final Object obj = getLast(output, kind); - // start of the tag - final int where = output.getSpanStart(obj); - // end of the tag - final int len = output.length(); - - final CharSequence extractedSpanText = output.subSequence(where, len); - output.delete(where, len); - return extractedSpanText; - } - - /** - * Get last marked position of a specific tag kind (private class) - */ - private static Object getLast(Editable text, Class kind) { - Object[] objs = text.getSpans(0, text.length(), kind); - if (objs.length == 0) { - return null; - } else { - for (int i = objs.length; i > 0; i--) { - if (text.getSpanFlags(objs[i - 1]) == Spannable.SPAN_MARK_MARK) { - return objs[i - 1]; - } - } - return null; - } - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/ssl/TLSSocketFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/ssl/TLSSocketFactory.kt index ce292dc2..eedba84d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/ssl/TLSSocketFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/ssl/TLSSocketFactory.kt @@ -16,8 +16,8 @@ package im.vector.matrix.android.internal.network.ssl -import im.vector.matrix.android.internal.legacy.util.Log import okhttp3.TlsVersion +import timber.log.Timber import java.io.IOException import java.net.InetAddress import java.net.Socket @@ -117,7 +117,7 @@ constructor(trustPinned: Array, acceptedTlsVersions: List senders; - - @SerializedName("not_senders") - public List notSenders; - - public List types; - - @SerializedName("not_types") - public List notTypes; - - public List rooms; - - @SerializedName("not_rooms") - public List notRooms; - - public boolean hasData() { - return limit != null +@JsonClass(generateAdapter = true) +data class Filter( + @Json(name = "limit") var limit: Int? = null, + @Json(name = "senders") var senders: MutableList? = null, + @Json(name = "not_senders") var notSenders: MutableList? = null, + @Json(name = "types") var types: MutableList? = null, + @Json(name = "not_types") var notTypes: MutableList? = null, + @Json(name = "rooms") var rooms: MutableList? = null, + @Json(name = "not_rooms") var notRooms: MutableList? = null +) { + fun hasData(): Boolean { + return (limit != null || senders != null || notSenders != null || types != null || notTypes != null || rooms != null - || notRooms != null; + || notRooms != null) } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/filter/FilterBody.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterBody.kt similarity index 53% rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/filter/FilterBody.java rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterBody.kt index 0806c6e8..3577d878 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/filter/FilterBody.java +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterBody.kt @@ -14,41 +14,28 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package im.vector.matrix.android.internal.legacy.rest.model.filter; +package im.vector.matrix.android.internal.session.filter -import com.google.gson.annotations.SerializedName; +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +import im.vector.matrix.android.internal.di.MoshiProvider -import im.vector.matrix.android.internal.legacy.util.JsonUtils; - -import java.util.List; /** * Class which can be parsed to a filter json string. Used for POST and GET * Have a look here for further information: * https://matrix.org/docs/spec/client_server/r0.3.0.html#post-matrix-client-r0-user-userid-filter */ -public class FilterBody { - public static final String LOG_TAG = FilterBody.class.getSimpleName(); +@JsonClass(generateAdapter = true) +internal data class FilterBody( + @Json(name = "event_fields") var eventFields: List? = null, + @Json(name = "event_format") var eventFormat: String? = null, + @Json(name = "presence") var presence: Filter? = null, + @Json(name = "account_data") var accountData: Filter? = null, + @Json(name = "room") var room: RoomFilter? = null +) { - @SerializedName("event_fields") - public List eventFields; - - @SerializedName("event_format") - public String eventFormat; - - public Filter presence; - - @SerializedName("account_data") - public Filter accountData; - - public RoomFilter room; - - @Override - public String toString() { - return LOG_TAG + toJSONString(); - } - - public String toJSONString() { - return JsonUtils.getGson(false).toJson(this); + fun toJSONString(): String { + return MoshiProvider.providesMoshi().adapter(FilterBody::class.java).toJson(this) } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/filter/FilterResponse.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterResponse.kt similarity index 77% rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/filter/FilterResponse.java rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterResponse.kt index 4fdb0054..1b3edf28 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/filter/FilterResponse.java +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterResponse.kt @@ -14,16 +14,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package im.vector.matrix.android.internal.legacy.rest.model.filter; +package im.vector.matrix.android.internal.session.filter -import com.google.gson.annotations.SerializedName; +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass /** * Represents the body which is the response when creating a filter on the server * https://matrix.org/docs/spec/client_server/r0.3.0.html#post-matrix-client-r0-user-userid-filter */ -public class FilterResponse { - - @SerializedName("filter_id") - public String filterId; -} +@JsonClass(generateAdapter = true) +data class FilterResponse( + @Json(name = "filter_id") var filterId: String +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/RoomEventFilter.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/RoomEventFilter.kt new file mode 100644 index 00000000..703c7565 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/RoomEventFilter.kt @@ -0,0 +1,57 @@ +/* + * Copyright 2018 Matthias Kesler + * Copyright 2018 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.matrix.android.internal.session.filter + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +import im.vector.matrix.android.internal.di.MoshiProvider + +/** + * Represents "RoomEventFilter" as mentioned in the SPEC + * https://matrix.org/docs/spec/client_server/r0.3.0.html#post-matrix-client-r0-user-userid-filter + */ +@JsonClass(generateAdapter = true) +data class RoomEventFilter( + @Json(name = "limit") var limit: Int? = null, + @Json(name = "not_senders") var notSenders: MutableList? = null, + @Json(name = "not_types") var notTypes: MutableList? = null, + @Json(name = "senders") var senders: MutableList? = null, + @Json(name = "types") var types: MutableList? = null, + @Json(name = "rooms") var rooms: MutableList? = null, + @Json(name = "not_rooms") var notRooms: List? = null, + @Json(name = "contains_url") var containsUrl: Boolean? = null, + @Json(name = "lazy_load_members") var lazyLoadMembers: Boolean? = null +) { + + fun toJSONString(): String { + return MoshiProvider.providesMoshi().adapter(RoomEventFilter::class.java).toJson(this) + } + + fun hasData(): Boolean { + return (limit != null + || notSenders != null + || notTypes != null + || senders != null + || types != null + || rooms != null + || notRooms != null + || containsUrl != null + || lazyLoadMembers != null) + } + +} + diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/filter/RoomFilter.java b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/RoomFilter.kt similarity index 55% rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/filter/RoomFilter.java rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/RoomFilter.kt index 1861a075..c432e1f2 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/legacy/rest/model/filter/RoomFilter.java +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/RoomFilter.kt @@ -14,42 +14,34 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package im.vector.matrix.android.internal.legacy.rest.model.filter; +package im.vector.matrix.android.internal.session.filter -import com.google.gson.annotations.SerializedName; - -import java.util.List; +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass /** * Represents "RoomFilter" as mentioned in the SPEC * https://matrix.org/docs/spec/client_server/r0.3.0.html#post-matrix-client-r0-user-userid-filter */ -public class RoomFilter { +@JsonClass(generateAdapter = true) +data class RoomFilter( + @Json(name = "not_rooms") var notRooms: List? = null, + @Json(name = "rooms") var rooms: List? = null, + @Json(name = "ephemeral") var ephemeral: RoomEventFilter? = null, + @Json(name = "include_leave") var includeLeave: Boolean? = null, + @Json(name = "state") var state: RoomEventFilter? = null, + @Json(name = "timeline") var timeline: RoomEventFilter? = null, + @Json(name = "account_data") var accountData: RoomEventFilter? = null +) { - @SerializedName("not_rooms") - public List notRooms; - - public List rooms; - - public RoomEventFilter ephemeral; - - @SerializedName("include_leave") - public Boolean includeLeave; - - public RoomEventFilter state; - - public RoomEventFilter timeline; - - @SerializedName("account_data") - public RoomEventFilter accountData; - - public boolean hasData() { - return notRooms != null + fun hasData(): Boolean { + return (notRooms != null || rooms != null || ephemeral != null || includeLeave != null || state != null || timeline != null - || accountData != null; + || accountData != null) } + } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/GetContextOfEventRequest.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/GetContextOfEventRequest.kt index 868d6953..f4f792d1 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/GetContextOfEventRequest.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/GetContextOfEventRequest.kt @@ -2,10 +2,10 @@ package im.vector.matrix.android.internal.session.room.timeline import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.util.Cancelable -import im.vector.matrix.android.internal.legacy.util.FilterUtil import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.session.room.RoomAPI import im.vector.matrix.android.internal.util.CancelableCoroutine +import im.vector.matrix.android.internal.util.FilterUtil import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/PaginationRequest.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/PaginationRequest.kt index 4f603b9b..e94d0387 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/PaginationRequest.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/PaginationRequest.kt @@ -3,10 +3,10 @@ package im.vector.matrix.android.internal.session.room.timeline import arrow.core.failure import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.util.Cancelable -import im.vector.matrix.android.internal.legacy.util.FilterUtil import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.session.room.RoomAPI import im.vector.matrix.android.internal.util.CancelableCoroutine +import im.vector.matrix.android.internal.util.FilterUtil import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/GroupSyncHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/GroupSyncHandler.kt index bf3163a3..27b2154a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/GroupSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/GroupSyncHandler.kt @@ -4,8 +4,8 @@ import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.api.session.room.model.MyMembership import im.vector.matrix.android.internal.database.model.GroupEntity import im.vector.matrix.android.internal.database.query.where -import im.vector.matrix.android.internal.legacy.rest.model.group.GroupsSyncResponse -import im.vector.matrix.android.internal.legacy.rest.model.group.InvitedGroupSync +import im.vector.matrix.android.internal.session.sync.model.GroupsSyncResponse +import im.vector.matrix.android.internal.session.sync.model.InvitedGroupSync import io.realm.Realm diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncRequest.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncRequest.kt index 6f4c5d3e..d3348dea 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncRequest.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncRequest.kt @@ -2,11 +2,11 @@ package im.vector.matrix.android.internal.session.sync import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.util.Cancelable -import im.vector.matrix.android.internal.legacy.rest.model.filter.FilterBody -import im.vector.matrix.android.internal.legacy.util.FilterUtil import im.vector.matrix.android.internal.network.executeRequest +import im.vector.matrix.android.internal.session.filter.FilterBody import im.vector.matrix.android.internal.session.sync.model.SyncResponse import im.vector.matrix.android.internal.util.CancelableCoroutine +import im.vector.matrix.android.internal.util.FilterUtil import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/SyncResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/SyncResponse.kt index bd5d7904..6bf6ae77 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/SyncResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/SyncResponse.kt @@ -2,7 +2,6 @@ package im.vector.matrix.android.internal.session.sync.model import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -import im.vector.matrix.android.internal.legacy.rest.model.group.GroupsSyncResponse // SyncResponse represents the request response for server sync v2. @JsonClass(generateAdapter = true) @@ -40,7 +39,8 @@ internal data class SyncResponse( /** * One time keys management */ - @Json(name = "device_one_time_keys_count") val deviceOneTimeKeysCount: DeviceOneTimeKeysCountSyncResponse? = null, + @Json(name = "device_one_time_keys_count") + val deviceOneTimeKeysCount: DeviceOneTimeKeysCountSyncResponse? = null, /** diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/FilterUtil.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/FilterUtil.kt new file mode 100644 index 00000000..02b498b7 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/FilterUtil.kt @@ -0,0 +1,140 @@ +/* + * Copyright 2018 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.matrix.android.internal.util + +import im.vector.matrix.android.internal.session.filter.Filter +import im.vector.matrix.android.internal.session.filter.FilterBody +import im.vector.matrix.android.internal.session.filter.RoomEventFilter +import im.vector.matrix.android.internal.session.filter.RoomFilter + +internal object FilterUtil { + + /** + * Patch the filterBody to enable or disable the data save mode + * + * + * If data save mode is on, FilterBody will contains + * "{\"room\": {\"ephemeral\": {\"types\": [\"m.receipt\"]}}, \"presence\":{\"notTypes\": [\"*\"]}}" + * + * @param filterBody filterBody to patch + * @param useDataSaveMode true to enable data save mode + */ + fun enableDataSaveMode(filterBody: FilterBody, useDataSaveMode: Boolean) { + if (useDataSaveMode) { + // Enable data save mode + if (filterBody.room == null) { + filterBody.room = RoomFilter() + } + filterBody.room?.let { room -> + if (room.ephemeral == null) { + room.ephemeral = RoomEventFilter() + } + room.ephemeral?.types?.let { types -> + if (!types.contains("m.receipt")) { + types.add("m.receipt") + } + } + } + + if (filterBody.presence == null) { + filterBody.presence = Filter() + } + filterBody.presence?.notTypes?.let { notTypes -> + if (!notTypes.contains("*")) { + notTypes.add("*") + } + } + } else { + + filterBody.room?.let { room -> + room.ephemeral?.types?.remove("m.receipt") + if (room.ephemeral?.types?.isEmpty() == true) { + room.ephemeral?.types = null + } + if (room.ephemeral?.hasData() == false) { + room.ephemeral = null + } + } + if (filterBody.room?.hasData() == false) { + filterBody.room = null + } + + filterBody.presence?.let { presence -> + presence.notTypes?.remove("*") + if (presence.notTypes?.isEmpty() == true) { + presence.notTypes = null + } + } + if (filterBody.presence?.hasData() == false) { + filterBody.presence = null + } + } + } + + /** + * Patch the filterBody to enable or disable the lazy loading + * + * + * If lazy loading is on, the filterBody will looks like + * {"room":{"state":{"lazy_load_members":true})} + * + * @param filterBody filterBody to patch + * @param useLazyLoading true to enable lazy loading + */ + fun enableLazyLoading(filterBody: FilterBody, useLazyLoading: Boolean) { + if (useLazyLoading) { + // Enable lazy loading + if (filterBody.room == null) { + filterBody.room = RoomFilter() + } + if (filterBody.room!!.state == null) { + filterBody.room!!.state = RoomEventFilter() + } + + filterBody.room!!.state!!.lazyLoadMembers = true + } else { + if (filterBody.room != null && filterBody.room!!.state != null) { + filterBody.room!!.state!!.lazyLoadMembers = null + + if (!filterBody.room!!.state!!.hasData()) { + filterBody.room!!.state = null + } + + if (!filterBody.room!!.hasData()) { + filterBody.room = null + } + } + } + } + + /** + * Create a RoomEventFilter + * + * @param withLazyLoading true when lazy loading is enabled + * @return a RoomEventFilter or null if lazy loading if OFF + */ + fun createRoomEventFilter(withLazyLoading: Boolean): RoomEventFilter? { + var roomEventFilter: RoomEventFilter? = null + + if (withLazyLoading) { + roomEventFilter = RoomEventFilter() + roomEventFilter.lazyLoadMembers = true + } + + return roomEventFilter + } +}