Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
A
AloqaIM-Android
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
AloqaIM-Android
Commits
5bbd3f7f
Unverified
Commit
5bbd3f7f
authored
Nov 28, 2017
by
Rafael Kellermann Streit
Committed by
GitHub
Nov 28, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #560 from RocketChat/develop
[RELEASE] Merge develop into master
parents
1f3713b3
92ee59e8
Changes
199
Hide whitespace changes
Inline
Side-by-side
Showing
199 changed files
with
3505 additions
and
3369 deletions
+3505
-3369
CONTRIBUTING.md
CONTRIBUTING.md
+1
-1
build.gradle
android-ddp/build.gradle
+0
-11
gen_listeners.py
android-ddp/gen_listeners.py
+0
-60
DDPClient.java
...-ddp/src/main/java/chat/rocket/android_ddp/DDPClient.java
+171
-61
DDPClientCallback.java
.../main/java/chat/rocket/android_ddp/DDPClientCallback.java
+1
-0
DDPClientImpl.java
.../src/main/java/chat/rocket/android_ddp/DDPClientImpl.java
+3
-2
DDPSubscription.java
...rc/main/java/chat/rocket/android_ddp/DDPSubscription.java
+1
-0
RxWebSocket.java
...src/main/java/chat/rocket/android_ddp/rx/RxWebSocket.java
+0
-1
build.gradle
app/build.gradle
+20
-48
RocketChatApplicationDebug.java
.../java/chat/rocket/android/RocketChatApplicationDebug.java
+1
-0
OkHttpHelper.kt
...src/debug/java/chat/rocket/android/helper/OkHttpHelper.kt
+1
-1
AndroidManifest.xml
app/src/main/AndroidManifest.xml
+30
-1
RocketChatApplication.java
.../main/java/chat/rocket/android/RocketChatApplication.java
+39
-23
RocketChatCache.java
app/src/main/java/chat/rocket/android/RocketChatCache.java
+72
-0
AbstractAuthedActivity.java
.../chat/rocket/android/activity/AbstractAuthedActivity.java
+39
-15
LoginActivity.java
...main/java/chat/rocket/android/activity/LoginActivity.java
+1
-1
LoginPresenter.java
...ain/java/chat/rocket/android/activity/LoginPresenter.java
+2
-3
MainActivity.java
.../main/java/chat/rocket/android/activity/MainActivity.java
+277
-272
MainContract.java
.../main/java/chat/rocket/android/activity/MainContract.java
+2
-0
MainPresenter.java
...main/java/chat/rocket/android/activity/MainPresenter.java
+222
-216
RoomActivity.kt
...in/java/chat/rocket/android/activity/room/RoomActivity.kt
+2
-1
DDPClientWrapper.java
...c/main/java/chat/rocket/android/api/DDPClientWrapper.java
+0
-137
FileUploadingHelper.java
...ain/java/chat/rocket/android/api/FileUploadingHelper.java
+3
-3
MethodCallHelper.java
...c/main/java/chat/rocket/android/api/MethodCallHelper.java
+70
-17
RaixPushHelper.java
...src/main/java/chat/rocket/android/api/RaixPushHelper.java
+3
-4
CookieInterceptor.java
.../java/chat/rocket/android/api/rest/CookieInterceptor.java
+1
-0
DefaultCookieProvider.java
...a/chat/rocket/android/api/rest/DefaultCookieProvider.java
+2
-2
DefaultServerPolicyApi.java
.../chat/rocket/android/api/rest/DefaultServerPolicyApi.java
+4
-3
ServerPolicyApi.java
...in/java/chat/rocket/android/api/rest/ServerPolicyApi.java
+2
-1
AbstractFragment.java
...n/java/chat/rocket/android/fragment/AbstractFragment.java
+1
-0
InputHostnameFragment.java
...et/android/fragment/add_server/InputHostnameFragment.java
+1
-0
InputHostnamePresenter.java
...t/android/fragment/add_server/InputHostnamePresenter.java
+4
-5
RoomContract.java
...a/chat/rocket/android/fragment/chatroom/RoomContract.java
+4
-0
RoomFragment.java
...a/chat/rocket/android/fragment/chatroom/RoomFragment.java
+18
-0
RoomPresenter.java
.../chat/rocket/android/fragment/chatroom/RoomPresenter.java
+14
-1
MessageOptionsDialogFragment.java
...ragment/chatroom/dialog/MessageOptionsDialogFragment.java
+4
-5
RoomListFragment.kt
...rocket/android/fragment/chatroom/list/RoomListFragment.kt
+20
-17
OAuthPresenter.java
...va/chat/rocket/android/fragment/oauth/OAuthPresenter.java
+1
-1
LoginContract.java
.../rocket/android/fragment/server_config/LoginContract.java
+1
-0
LoginFragment.java
.../rocket/android/fragment/server_config/LoginFragment.java
+1
-0
LoginPresenter.java
...rocket/android/fragment/server_config/LoginPresenter.java
+2
-2
RetryLoginPresenter.java
...t/android/fragment/server_config/RetryLoginPresenter.java
+1
-1
TwoStepAuthPresenter.java
.../android/fragment/server_config/TwoStepAuthPresenter.java
+2
-1
SidebarMainContract.java
.../rocket/android/fragment/sidebar/SidebarMainContract.java
+4
-3
SidebarMainFragment.java
.../rocket/android/fragment/sidebar/SidebarMainFragment.java
+1
-0
AddDirectMessageDialogFragment.java
...agment/sidebar/dialog/AddDirectMessageDialogFragment.java
+5
-4
AbsoluteUrlHelper.java
...in/java/chat/rocket/android/helper/AbsoluteUrlHelper.java
+2
-2
DateTime.java
app/src/main/java/chat/rocket/android/helper/DateTime.java
+19
-1
FileUploadHelper.java
...ain/java/chat/rocket/android/helper/FileUploadHelper.java
+3
-1
GcmPushSettingHelper.java
...java/chat/rocket/android/helper/GcmPushSettingHelper.java
+4
-4
RxHelper.java
app/src/main/java/chat/rocket/android/helper/RxHelper.java
+6
-5
ServerPolicyApiValidationHelper.java
...ocket/android/helper/ServerPolicyApiValidationHelper.java
+1
-2
ServerPolicyHelper.java
...n/java/chat/rocket/android/helper/ServerPolicyHelper.java
+3
-2
AbstractMessageViewHolder.java
...roid/layouthelper/chatroom/AbstractMessageViewHolder.java
+3
-1
MessageListAdapter.java
...ket/android/layouthelper/chatroom/MessageListAdapter.java
+1
-0
MessageNormalViewHolder.java
...ndroid/layouthelper/chatroom/MessageNormalViewHolder.java
+1
-0
MessagePopup.java
...at/rocket/android/layouthelper/chatroom/MessagePopup.java
+9
-1
RoomFileListAdapter.kt
...android/layouthelper/chatroom/list/RoomFileListAdapter.kt
+13
-2
RoomUserAdapter.java
...t/android/layouthelper/chatroom/list/RoomUserAdapter.java
+3
-2
ChannelRoomListHeader.java
...layouthelper/chatroom/roomlist/ChannelRoomListHeader.java
+2
-1
DirectMessageRoomListHeader.java
...helper/chatroom/roomlist/DirectMessageRoomListHeader.java
+2
-1
FavoriteRoomListHeader.java
...ayouthelper/chatroom/roomlist/FavoriteRoomListHeader.java
+2
-1
RoomListAdapter.java
...droid/layouthelper/chatroom/roomlist/RoomListAdapter.java
+3
-2
RoomListHeader.java
...ndroid/layouthelper/chatroom/roomlist/RoomListHeader.java
+2
-1
UnreadRoomListHeader.java
.../layouthelper/chatroom/roomlist/UnreadRoomListHeader.java
+2
-1
OAuthProviderInfo.java
.../rocket/android/layouthelper/oauth/OAuthProviderInfo.java
+1
-0
SuggestUserAdapter.java
...droid/layouthelper/sidebar/dialog/SuggestUserAdapter.java
+3
-2
BackgroundActionButtonHandler.java
...at/rocket/android/push/BackgroundActionButtonHandler.java
+1
-1
PushManager.kt
app/src/main/java/chat/rocket/android/push/PushManager.kt
+701
-0
PushNotificationHandler.java
...ava/chat/rocket/android/push/PushNotificationHandler.java
+0
-986
GCMIntentService.java
...n/java/chat/rocket/android/push/gcm/GCMIntentService.java
+6
-6
GcmInstanceIDListenerService.java
...rocket/android/push/gcm/GcmInstanceIDListenerService.java
+5
-4
ConnectivityManagerApi.java
...a/chat/rocket/android/service/ConnectivityManagerApi.java
+14
-8
ConnectivityManagerInternal.java
...t/rocket/android/service/ConnectivityManagerInternal.java
+1
-4
ConnectivityServiceInterface.java
.../rocket/android/service/ConnectivityServiceInterface.java
+1
-1
DDPClientRef.java
...c/main/java/chat/rocket/android/service/DDPClientRef.java
+0
-10
RealmBasedConnectivityManager.java
...rocket/android/service/RealmBasedConnectivityManager.java
+253
-219
RocketChatService.java
...n/java/chat/rocket/android/service/RocketChatService.java
+127
-105
RocketChatWebSocketThread.java
...hat/rocket/android/service/RocketChatWebSocketThread.java
+347
-388
ServerConnectivity.java
.../java/chat/rocket/android/service/ServerConnectivity.java
+27
-1
AbstractDDPDocEventSubscriber.java
...et/android/service/ddp/AbstractDDPDocEventSubscriber.java
+13
-14
AbstractBaseSubscriber.java
...cket/android/service/ddp/base/AbstractBaseSubscriber.java
+4
-5
ActiveUsersSubscriber.java
...ocket/android/service/ddp/base/ActiveUsersSubscriber.java
+5
-6
LoginServiceConfigurationSubscriber.java
...service/ddp/base/LoginServiceConfigurationSubscriber.java
+4
-5
UserDataSubscriber.java
...t/rocket/android/service/ddp/base/UserDataSubscriber.java
+5
-6
AbstractStreamNotifyEventSubscriber.java
...rvice/ddp/stream/AbstractStreamNotifyEventSubscriber.java
+4
-5
AbstractStreamNotifyUserEventSubscriber.java
...e/ddp/stream/AbstractStreamNotifyUserEventSubscriber.java
+2
-4
StreamNotifyUserSubscriptionsChanged.java
...vice/ddp/stream/StreamNotifyUserSubscriptionsChanged.java
+5
-5
StreamRoomMessage.java
.../rocket/android/service/ddp/stream/StreamRoomMessage.java
+5
-5
StreamRoomMessageManager.java
...et/android/service/internal/StreamRoomMessageManager.java
+3
-6
AbstractModelObserver.java
...ocket/android/service/observer/AbstractModelObserver.java
+3
-6
CurrentUserObserver.java
.../rocket/android/service/observer/CurrentUserObserver.java
+9
-9
DeletedMessageObserver.java
...cket/android/service/observer/DeletedMessageObserver.java
+84
-0
FileUploadingToUrlObserver.java
.../android/service/observer/FileUploadingToUrlObserver.java
+9
-8
FileUploadingWithUfsObserver.java
...ndroid/service/observer/FileUploadingWithUfsObserver.java
+9
-8
GcmPushRegistrationObserver.java
...android/service/observer/GcmPushRegistrationObserver.java
+3
-5
GetUsersOfRoomsProcedureObserver.java
...id/service/observer/GetUsersOfRoomsProcedureObserver.java
+8
-7
LoadMessageProcedureObserver.java
...ndroid/service/observer/LoadMessageProcedureObserver.java
+8
-6
MethodCallObserver.java
...t/rocket/android/service/observer/MethodCallObserver.java
+4
-4
NewMessageObserver.java
...t/rocket/android/service/observer/NewMessageObserver.java
+8
-7
PushSettingsObserver.java
...rocket/android/service/observer/PushSettingsObserver.java
+6
-6
SessionObserver.java
...chat/rocket/android/service/observer/SessionObserver.java
+9
-9
TokenLoginObserver.java
...t/rocket/android/service/observer/TokenLoginObserver.java
+0
-42
slide_in.xml
app/src/main/res/anim/slide_in.xml
+10
-0
slide_out.xml
app/src/main/res/anim/slide_out.xml
+9
-0
strings.xml
app/src/main/res/values/strings.xml
+4
-1
RocketChatCacheTest.kt
...rc/test/kotlin/chat.rocket.android/RocketChatCacheTest.kt
+0
-42
PushManagerTest.kt
...c/test/kotlin/chat.rocket.android/push/PushManagerTest.kt
+152
-0
RestApiHelperTest.kt
.../kotlin/chat/rocket/android/api/rest/RestApiHelperTest.kt
+54
-54
UrlHelperTest.kt
...c/test/kotlin/chat/rocket/android/helper/UrlHelperTest.kt
+14
-14
build.gradle
build.gradle
+29
-8
circle.yml
circle.yml
+8
-3
dependencies.gradle
dependencies.gradle
+10
-6
gradle-wrapper.properties
gradle/wrapper/gradle-wrapper.properties
+2
-2
build.gradle
log-wrapper/build.gradle
+0
-8
build.gradle
persistence-realm/build.gradle
+1
-18
Migration.java
...rc/main/java/chat/rocket/persistence/realm/Migration.java
+20
-6
RealmAutoCompleteAdapter.java
...at/rocket/persistence/realm/RealmAutoCompleteAdapter.java
+4
-3
RealmHelper.java
.../main/java/chat/rocket/persistence/realm/RealmHelper.java
+29
-5
RealmListObserver.java
...java/chat/rocket/persistence/realm/RealmListObserver.java
+2
-2
RealmStore.java
...c/main/java/chat/rocket/persistence/realm/RealmStore.java
+5
-7
RocketChatPersistenceRealm.java
.../rocket/persistence/realm/RocketChatPersistenceRealm.java
+1
-0
RealmBasedServerInfo.java
...rocket/persistence/realm/models/RealmBasedServerInfo.java
+5
-4
RealmEmail.java
.../chat/rocket/persistence/realm/models/ddp/RealmEmail.java
+1
-2
RealmMessage.java
...hat/rocket/persistence/realm/models/ddp/RealmMessage.java
+4
-3
RealmMeteorLoginServiceConfiguration.java
...ealm/models/ddp/RealmMeteorLoginServiceConfiguration.java
+1
-2
RealmPermission.java
.../rocket/persistence/realm/models/ddp/RealmPermission.java
+4
-3
RealmPreferences.java
...rocket/persistence/realm/models/ddp/RealmPreferences.java
+1
-2
RealmPublicSetting.java
...cket/persistence/realm/models/ddp/RealmPublicSetting.java
+3
-2
RealmRole.java
...a/chat/rocket/persistence/realm/models/ddp/RealmRole.java
+2
-2
RealmRoom.java
...a/chat/rocket/persistence/realm/models/ddp/RealmRoom.java
+3
-3
RealmRoomRole.java
...at/rocket/persistence/realm/models/ddp/RealmRoomRole.java
+4
-3
RealmSettings.java
...at/rocket/persistence/realm/models/ddp/RealmSettings.java
+1
-2
RealmSpotlightRoom.java
...cket/persistence/realm/models/ddp/RealmSpotlightRoom.java
+1
-2
RealmSpotlightUser.java
...cket/persistence/realm/models/ddp/RealmSpotlightUser.java
+1
-2
GcmPushRegistration.java
...ersistence/realm/models/internal/GcmPushRegistration.java
+4
-4
LoadMessageProcedure.java
...rsistence/realm/models/internal/LoadMessageProcedure.java
+1
-2
MethodCall.java
.../rocket/persistence/realm/models/internal/MethodCall.java
+4
-2
RealmSession.java
...ocket/persistence/realm/models/internal/RealmSession.java
+5
-4
RocketChatServerModule.java
...ket/persistence/realm/modules/RocketChatServerModule.java
+1
-2
RealmLoginServiceConfigurationRepository.java
...epositories/RealmLoginServiceConfigurationRepository.java
+10
-11
RealmMessageRepository.java
...ersistence/realm/repositories/RealmMessageRepository.java
+21
-24
RealmPermissionRepository.java
...istence/realm/repositories/RealmPermissionRepository.java
+7
-8
RealmPublicSettingRepository.java
...ence/realm/repositories/RealmPublicSettingRepository.java
+7
-8
RealmRepository.java
...ocket/persistence/realm/repositories/RealmRepository.java
+3
-2
RealmRoomRepository.java
...t/persistence/realm/repositories/RealmRoomRepository.java
+21
-31
RealmRoomRoleRepository.java
...rsistence/realm/repositories/RealmRoomRoleRepository.java
+7
-8
RealmServerInfoRepository.java
...istence/realm/repositories/RealmServerInfoRepository.java
+6
-7
RealmSessionRepository.java
...ersistence/realm/repositories/RealmSessionRepository.java
+10
-15
RealmSpotlightRepository.kt
...ersistence/realm/repositories/RealmSpotlightRepository.kt
+4
-6
RealmSpotlightRoomRepository.java
...ence/realm/repositories/RealmSpotlightRoomRepository.java
+7
-8
RealmSpotlightUserRepository.java
...ence/realm/repositories/RealmSpotlightUserRepository.java
+7
-8
RealmUserRepository.java
...t/persistence/realm/repositories/RealmUserRepository.java
+8
-14
build.gradle
rocket-chat-android-widgets/build.gradle
+5
-17
RocketChatAvatar.java
...ain/java/chat/rocket/android/widget/RocketChatAvatar.java
+3
-1
IconProvider.java
.../java/chat/rocket/android/widget/helper/IconProvider.java
+1
-0
InlineHightlighter.java
...chat/rocket/android/widget/helper/InlineHightlighter.java
+1
-0
LinkMovementMethodCompat.java
...ocket/android/widget/helper/LinkMovementMethodCompat.java
+0
-1
Linkify.java
.../main/java/chat/rocket/android/widget/helper/Linkify.java
+1
-0
ExtraActionPickerDialogFragment.java
...roid/widget/internal/ExtraActionPickerDialogFragment.java
+1
-0
MessageExtraActionListAdapter.java
...id/widget/layouthelper/MessageExtraActionListAdapter.java
+1
-0
RocketChatMessageAttachmentsLayout.java
...id/widget/message/RocketChatMessageAttachmentsLayout.java
+6
-4
RocketChatMessageLayout.java
...ocket/android/widget/message/RocketChatMessageLayout.java
+1
-0
RocketChatMessageUrlsLayout.java
...t/android/widget/message/RocketChatMessageUrlsLayout.java
+3
-1
AutocompleteManager.java
...roid/widget/message/autocomplete/AutocompleteManager.java
+6
-5
AutocompleteSource.java
...droid/widget/message/autocomplete/AutocompleteSource.java
+1
-0
ChannelSource.java
...id/widget/message/autocomplete/channel/ChannelSource.java
+6
-6
UserSource.java
.../android/widget/message/autocomplete/user/UserSource.java
+6
-5
message_composer.xml
...-android-widgets/src/main/res/layout/message_composer.xml
+31
-26
server_row.xml
...t-chat-android-widgets/src/main/res/layout/server_row.xml
+1
-1
build.gradle
rocket-chat-core/build.gradle
+4
-13
SyncState.java
...t-chat-core/src/main/java/chat/rocket/core/SyncState.java
+3
-0
AutocompleteChannelInteractor.kt
.../rocket/core/interactors/AutocompleteChannelInteractor.kt
+2
-3
AutocompleteUserInteractor.kt
...hat/rocket/core/interactors/AutocompleteUserInteractor.kt
+1
-1
CanCreateRoomInteractor.kt
...a/chat/rocket/core/interactors/CanCreateRoomInteractor.kt
+2
-3
EditMessageInteractor.kt
...ava/chat/rocket/core/interactors/EditMessageInteractor.kt
+8
-2
MessageInteractor.kt
...in/java/chat/rocket/core/interactors/MessageInteractor.kt
+12
-5
PermissionInteractor.kt
...java/chat/rocket/core/interactors/PermissionInteractor.kt
+3
-1
RoomInteractor.kt
.../main/java/chat/rocket/core/interactors/RoomInteractor.kt
+1
-1
SessionInteractor.kt
...in/java/chat/rocket/core/interactors/SessionInteractor.kt
+2
-3
UserInteractor.java
...ain/java/chat/rocket/core/interactors/UserInteractor.java
+2
-2
Attachment.java
...ore/src/main/java/chat/rocket/core/models/Attachment.java
+1
-0
Message.java
...t-core/src/main/java/chat/rocket/core/models/Message.java
+1
-0
User.java
...chat-core/src/main/java/chat/rocket/core/models/User.java
+1
-0
WebContent.java
...ore/src/main/java/chat/rocket/core/models/WebContent.java
+1
-0
LoginServiceConfigurationRepository.java
...ore/repositories/LoginServiceConfigurationRepository.java
+3
-2
MessageRepository.java
...java/chat/rocket/core/repositories/MessageRepository.java
+3
-2
PermissionRepository.java
...a/chat/rocket/core/repositories/PermissionRepository.java
+1
-1
PublicSettingRepository.java
...hat/rocket/core/repositories/PublicSettingRepository.java
+1
-1
RoomRepository.java
...in/java/chat/rocket/core/repositories/RoomRepository.java
+3
-2
RoomRoleRepository.java
...ava/chat/rocket/core/repositories/RoomRoleRepository.java
+1
-1
ServerInfoRepository.java
...a/chat/rocket/core/repositories/ServerInfoRepository.java
+1
-2
SessionRepository.java
...java/chat/rocket/core/repositories/SessionRepository.java
+2
-2
SpotlightRoomRepository.java
...hat/rocket/core/repositories/SpotlightRoomRepository.java
+2
-2
SpotlightUserRepository.java
...hat/rocket/core/repositories/SpotlightUserRepository.java
+2
-2
UserRepository.kt
...main/java/chat/rocket/core/repositories/UserRepository.kt
+1
-1
AutocompleteChannelInteractorTest.java
...t/core/interactors/AutocompleteChannelInteractorTest.java
+11
-4
EditMessageInteractorTest.kt
...chat/rocket/core/interactors/EditMessageInteractorTest.kt
+4
-2
PermissionInteractorTest.kt
.../chat/rocket/core/interactors/PermissionInteractorTest.kt
+2
-2
No files found.
CONTRIBUTING.md
View file @
5bbd3f7f
...
...
@@ -19,4 +19,4 @@ git clone https://github.com/RocketChat/Rocket.Chat.Android
### Code style guide
Before submitting a PR you should follow our
[
Coding Style
](
https://github.com/RocketChat/
Rocket.Chat.Android/blob/develop
/CODING_STYLE.md
)
.
Before submitting a PR you should follow our
[
Coding Style
](
https://github.com/RocketChat/
java-code-styles/blob/master
/CODING_STYLE.md
)
.
android-ddp/build.gradle
View file @
5bbd3f7f
apply
plugin:
'com.android.library'
apply
plugin:
'me.tatarka.retrolambda'
buildscript
{
repositories
{
jcenter
()
}
dependencies
{
classpath
'com.android.tools.build:gradle:2.3.3'
classpath
'me.tatarka:gradle-retrolambda:3.6.1'
classpath
'me.tatarka.retrolambda.projectlombok:lombok.ast:0.2.3.a2'
}
}
android
{
compileSdkVersion
rootProject
.
ext
.
compileSdkVersion
buildToolsVersion
rootProject
.
ext
.
buildToolsVersion
...
...
android-ddp/gen_listeners.py
deleted
100644 → 0
View file @
1f3713b3
# -*- coding:utf-8 -*-
a
=
'''
@Override
public void onOpen(WebSocket webSocket, Response response) {
}
@Override
public void onFailure(IOException e, Response response) {
}
@Override
public void onMessage(ResponseBody responseBody) throws IOException {
}
@Override
public void onPong(Buffer payload) {
}
@Override
public void onClose(int code, String reason) {
}
'''
.
strip
()
.
split
(
'@Override'
)
for
m
in
a
[
1
:]:
m
=
" @Override
\n
"
+
m
.
strip
()
mn
=
m
.
split
(
"
\n
"
)[
1
]
.
strip
()
.
split
(
" "
)[
2
]
.
split
(
"("
)[
0
]
if
mn
.
startswith
(
"on"
):
d
=
dict
()
d
[
"classname"
]
=
mn
[
2
:]
params
=
[
p
for
p
in
" "
.
join
(
m
.
split
(
"
\n
"
)[
1
]
.
strip
()[:
-
1
]
.
split
(
" throws "
)[
0
]
.
split
(
" "
)[
2
:])
.
strip
()[
len
(
mn
)
+
1
:
-
1
]
.
split
(
", "
)
if
p
.
split
(
" "
)[
0
]
!=
"WebSocket"
]
d
[
"params"
]
=
""
.
join
([
", "
+
p
for
p
in
params
])
paramnames
=
[
p
.
split
(
" "
)[
-
1
]
for
p
in
params
]
d
[
"paramdefs"
]
=
"
\n
"
.
join
([
" public "
+
p
+
";"
for
p
in
params
])
d
[
"thisis"
]
=
"
\n
"
.
join
([
" this.{param} = {param};"
.
format
(
param
=
p
)
for
p
in
paramnames
])
# print '''
# public static class {classname} extends Base {{
# {paramdefs}
# public {classname}(WebSocket websocket{params}) {{
# super("{classname}", websocket);
# {thisis}
# }}
# }}'''.format(**d)
######################
x
=
m
.
split
(
"
\n
"
)
x
[
2
]
=
''' mSubscriber.onNext(new RxWebSocketCallback.{classname}(mWebSocket, {params}));'''
.
format
(
classname
=
mn
[
2
:],
params
=
", "
.
join
(
paramnames
))
print
"
\n
"
.
join
(
x
)
android-ddp/src/main/java/chat/rocket/android_ddp/DDPClient.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android_ddp
;
import
io.reactivex.Flowable
;
import
io.reactivex.Maybe
;
import
io.reactivex.annotations.Nullable
;
import
android.text.TextUtils
;
import
org.json.JSONArray
;
import
org.json.JSONException
;
import
java.util.UUID
;
import
java.util.concurrent.atomic.AtomicReference
;
import
bolts.Task
;
import
bolts.TaskCompletionSource
;
import
chat.rocket.android.log.RCLog
;
import
chat.rocket.android_ddp.rx.RxWebSocketCallback
;
import
io.reactivex.Flowable
;
import
io.reactivex.Maybe
;
import
io.reactivex.annotations.NonNull
;
import
io.reactivex.annotations.Nullable
;
import
okhttp3.OkHttpClient
;
public
class
DDPClient
{
// reference: https://github.com/eddflrs/meteor-ddp/blob/master/meteor-ddp.js
private
final
DDPClientImpl
impl
;
public
DDPClient
(
OkHttpClient
client
)
{
impl
=
new
DDPClientImpl
(
this
,
client
);
}
public
Task
<
DDPClientCallback
.
Connect
>
connect
(
String
url
)
{
return
connect
(
url
,
null
);
}
public
Task
<
DDPClientCallback
.
Connect
>
connect
(
String
url
,
String
session
)
{
TaskCompletionSource
<
DDPClientCallback
.
Connect
>
task
=
new
TaskCompletionSource
<>();
impl
.
connect
(
task
,
url
,
session
);
return
task
.
getTask
();
}
public
Task
<
DDPClientCallback
.
Ping
>
ping
(
@Nullable
String
id
)
{
TaskCompletionSource
<
DDPClientCallback
.
Ping
>
task
=
new
TaskCompletionSource
<>();
impl
.
ping
(
task
,
id
);
return
task
.
getTask
();
}
public
Maybe
<
DDPClientCallback
.
Base
>
doPing
(
@Nullable
String
id
)
{
return
impl
.
ping
(
id
);
}
public
Task
<
DDPClientCallback
.
RPC
>
rpc
(
String
method
,
JSONArray
params
,
String
id
,
long
timeoutMs
)
{
TaskCompletionSource
<
DDPClientCallback
.
RPC
>
task
=
new
TaskCompletionSource
<>();
impl
.
rpc
(
task
,
method
,
params
,
id
,
timeoutMs
);
return
task
.
getTask
();
}
public
Task
<
DDPSubscription
.
Ready
>
sub
(
String
id
,
String
name
,
JSONArray
params
)
{
TaskCompletionSource
<
DDPSubscription
.
Ready
>
task
=
new
TaskCompletionSource
<>();
impl
.
sub
(
task
,
name
,
params
,
id
);
return
task
.
getTask
();
}
public
Task
<
DDPSubscription
.
NoSub
>
unsub
(
String
id
)
{
TaskCompletionSource
<
DDPSubscription
.
NoSub
>
task
=
new
TaskCompletionSource
<>();
impl
.
unsub
(
task
,
id
);
return
task
.
getTask
();
}
public
Flowable
<
DDPSubscription
.
Event
>
getSubscriptionCallback
()
{
return
impl
.
getDDPSubscription
();
}
public
Task
<
RxWebSocketCallback
.
Close
>
getOnCloseCallback
()
{
return
impl
.
getOnCloseCallback
();
}
public
void
close
()
{
impl
.
close
(
1000
,
"closed by DDPClient#close()"
);
}
// reference: https://github.com/eddflrs/meteor-ddp/blob/master/meteor-ddp.js
public
static
final
int
REASON_CLOSED_BY_USER
=
1000
;
public
static
final
int
REASON_NETWORK_ERROR
=
1001
;
private
static
volatile
DDPClient
singleton
;
private
static
volatile
OkHttpClient
client
;
private
final
DDPClientImpl
impl
;
private
final
AtomicReference
<
String
>
hostname
=
new
AtomicReference
<>();
public
static
void
initialize
(
OkHttpClient
okHttpClient
)
{
client
=
okHttpClient
;
}
public
static
DDPClient
get
()
{
DDPClient
result
=
singleton
;
if
(
result
==
null
)
{
synchronized
(
DDPClient
.
class
)
{
result
=
singleton
;
if
(
result
==
null
)
{
singleton
=
result
=
new
DDPClient
(
client
);
}
}
}
return
result
;
}
private
DDPClient
(
OkHttpClient
client
)
{
impl
=
new
DDPClientImpl
(
this
,
client
);
}
private
Task
<
DDPClientCallback
.
Connect
>
connect
(
String
url
,
String
session
)
{
hostname
.
set
(
url
);
TaskCompletionSource
<
DDPClientCallback
.
Connect
>
task
=
new
TaskCompletionSource
<>();
impl
.
connect
(
task
,
url
,
session
);
return
task
.
getTask
();
}
private
Task
<
DDPClientCallback
.
Ping
>
ping
(
@Nullable
String
id
)
{
TaskCompletionSource
<
DDPClientCallback
.
Ping
>
task
=
new
TaskCompletionSource
<>();
impl
.
ping
(
task
,
id
);
return
task
.
getTask
();
}
private
Maybe
<
DDPClientCallback
.
Base
>
doPing
(
@Nullable
String
id
)
{
return
impl
.
ping
(
id
);
}
private
Task
<
DDPSubscription
.
Ready
>
sub
(
String
id
,
String
name
,
JSONArray
params
)
{
TaskCompletionSource
<
DDPSubscription
.
Ready
>
task
=
new
TaskCompletionSource
<>();
impl
.
sub
(
task
,
name
,
params
,
id
);
return
task
.
getTask
();
}
private
Task
<
DDPSubscription
.
NoSub
>
unsub
(
String
id
)
{
TaskCompletionSource
<
DDPSubscription
.
NoSub
>
task
=
new
TaskCompletionSource
<>();
impl
.
unsub
(
task
,
id
);
return
task
.
getTask
();
}
public
Task
<
RxWebSocketCallback
.
Close
>
getOnCloseCallback
()
{
return
impl
.
getOnCloseCallback
();
}
public
void
close
()
{
impl
.
close
(
REASON_CLOSED_BY_USER
,
"closed by DDPClient#close()"
);
}
/**
* check WebSocket connectivity with ping.
*/
public
Task
<
Void
>
ping
()
{
final
String
pingId
=
UUID
.
randomUUID
().
toString
();
RCLog
.
d
(
"ping[%s] >"
,
pingId
);
return
ping
(
pingId
)
.
continueWithTask
(
task
->
{
if
(
task
.
isFaulted
())
{
RCLog
.
d
(
task
.
getError
(),
"ping[%s] xxx failed xxx"
,
pingId
);
return
Task
.
forError
(
task
.
getError
());
}
else
{
RCLog
.
d
(
"pong[%s] <"
,
pingId
);
return
Task
.
forResult
(
null
);
}
});
}
/**
* check WebSocket connectivity with ping.
*/
public
Maybe
<
DDPClientCallback
.
Base
>
doPing
()
{
final
String
pingId
=
UUID
.
randomUUID
().
toString
();
RCLog
.
d
(
"ping[%s] >"
,
pingId
);
return
doPing
(
pingId
);
}
/**
* Connect to WebSocket server with DDP client.
*/
public
Task
<
DDPClientCallback
.
Connect
>
connect
(
@NonNull
String
hostname
,
@Nullable
String
session
,
boolean
usesSecureConnection
)
{
final
String
protocol
=
usesSecureConnection
?
"wss://"
:
"ws://"
;
return
connect
(
protocol
+
hostname
+
"/websocket"
,
session
);
}
/**
* Subscribe with DDP client.
*/
public
Task
<
DDPSubscription
.
Ready
>
subscribe
(
final
String
name
,
JSONArray
param
)
{
final
String
subscriptionId
=
UUID
.
randomUUID
().
toString
();
RCLog
.
d
(
"sub:[%s]> %s(%s)"
,
subscriptionId
,
name
,
param
);
return
sub
(
subscriptionId
,
name
,
param
);
}
/**
* Unsubscribe with DDP client.
*/
public
Task
<
DDPSubscription
.
NoSub
>
unsubscribe
(
final
String
subscriptionId
)
{
RCLog
.
d
(
"unsub:[%s]>"
,
subscriptionId
);
return
unsub
(
subscriptionId
);
}
/**
* Returns Observable for handling DDP subscription.
*/
public
Flowable
<
DDPSubscription
.
Event
>
getSubscriptionCallback
()
{
return
impl
.
getDDPSubscription
();
}
/**
* Execute raw RPC.
*/
public
Task
<
DDPClientCallback
.
RPC
>
rpc
(
String
methodCallId
,
String
methodName
,
String
params
,
long
timeoutMs
)
{
TaskCompletionSource
<
DDPClientCallback
.
RPC
>
task
=
new
TaskCompletionSource
<>();
RCLog
.
d
(
"rpc:[%s]> %s(%s) timeout=%d"
,
methodCallId
,
methodName
,
params
,
timeoutMs
);
if
(
TextUtils
.
isEmpty
(
params
))
{
impl
.
rpc
(
task
,
methodName
,
null
,
methodCallId
,
timeoutMs
);
return
task
.
getTask
().
continueWithTask
(
task_
->
{
if
(
task_
.
isFaulted
())
{
RCLog
.
d
(
"rpc:[%s]< error = %s"
,
methodCallId
,
task_
.
getError
());
}
else
{
RCLog
.
d
(
"rpc:[%s]< result = %s"
,
methodCallId
,
task_
.
getResult
().
result
);
}
return
task_
;
});
}
try
{
impl
.
rpc
(
task
,
methodName
,
new
JSONArray
(
params
),
methodCallId
,
timeoutMs
);
return
task
.
getTask
().
continueWithTask
(
task_
->
{
if
(
task_
.
isFaulted
())
{
RCLog
.
d
(
"rpc:[%s]< error = %s"
,
methodCallId
,
task_
.
getError
());
}
else
{
RCLog
.
d
(
"rpc:[%s]< result = %s"
,
methodCallId
,
task_
.
getResult
().
result
);
}
return
task_
;
});
}
catch
(
JSONException
exception
)
{
return
Task
.
forError
(
exception
);
}
}
}
android-ddp/src/main/java/chat/rocket/android_ddp/DDPClientCallback.java
View file @
5bbd3f7f
...
...
@@ -2,6 +2,7 @@ package chat.rocket.android_ddp;
import
android.support.annotation.NonNull
;
import
android.support.annotation.Nullable
;
import
org.json.JSONObject
;
public
class
DDPClientCallback
{
...
...
android-ddp/src/main/java/chat/rocket/android_ddp/DDPClientImpl.java
View file @
5bbd3f7f
...
...
@@ -52,14 +52,14 @@ public class DDPClientImpl {
}
}
public
void
connect
(
final
TaskCompletionSource
<
DDPClientCallback
.
Connect
>
task
,
final
String
url
,
/* package */
void
connect
(
final
TaskCompletionSource
<
DDPClientCallback
.
Connect
>
task
,
final
String
url
,
String
session
)
{
try
{
flowable
=
websocket
.
connect
(
url
).
autoConnect
(
2
);
CompositeDisposable
disposables
=
new
CompositeDisposable
();
disposables
.
add
(
flowable
.
retry
().
filter
(
callback
->
callback
instanceof
RxWebSocketCallback
.
Open
)
flowable
.
filter
(
callback
->
callback
instanceof
RxWebSocketCallback
.
Open
)
.
subscribe
(
callback
->
sendMessage
(
"connect"
,
...
...
@@ -115,6 +115,7 @@ public class DDPClientImpl {
if
(
requested
)
{
return
flowable
.
filter
(
callback
->
callback
instanceof
RxWebSocketCallback
.
Message
)
.
timeout
(
8
,
TimeUnit
.
SECONDS
)
.
map
(
callback
->
((
RxWebSocketCallback
.
Message
)
callback
).
responseBodyString
)
.
map
(
DDPClientImpl:
:
toJson
)
.
filter
(
response
->
"pong"
.
equalsIgnoreCase
(
extractMsg
(
response
)))
...
...
android-ddp/src/main/java/chat/rocket/android_ddp/DDPSubscription.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android_ddp
;
import
android.support.annotation.NonNull
;
import
org.json.JSONArray
;
import
org.json.JSONObject
;
...
...
android-ddp/src/main/java/chat/rocket/android_ddp/rx/RxWebSocket.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android_ddp
.
rx
;
import
java.io.IOException
;
import
java.util.concurrent.TimeUnit
;
import
chat.rocket.android.log.RCLog
;
import
io.reactivex.BackpressureStrategy
;
...
...
app/build.gradle
View file @
5bbd3f7f
...
...
@@ -8,35 +8,10 @@ repositories {
apply
plugin:
'kotlin-android'
apply
plugin:
'kotlin-android-extensions'
apply
plugin:
'me.tatarka.retrolambda'
apply
plugin:
'com.jakewharton.hugo'
apply
plugin:
'com.github.triplet.play'
apply
from:
'../config/quality/quality.gradle'
buildscript
{
repositories
{
jcenter
()
mavenCentral
()
maven
{
url
'https://maven.fabric.io/public'
}
}
dependencies
{
classpath
'com.android.tools.build:gradle:2.3.3'
classpath
"org.jetbrains.kotlin:kotlin-gradle-plugin:$rootProject.ext.kotlinVersion"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath
'me.tatarka:gradle-retrolambda:3.5.0'
classpath
'me.tatarka.retrolambda.projectlombok:lombok.ast:0.2.3.a2'
classpath
'io.realm:realm-gradle-plugin:2.3.1'
classpath
'com.jakewharton.hugo:hugo-plugin:1.2.1'
classpath
'com.google.gms:google-services:3.0.0'
classpath
'com.github.triplet.gradle:play-publisher:1.1.5'
classpath
'io.fabric.tools:gradle:1.+'
}
// Exclude the version that the android plugin depends on.
configurations
.
classpath
.
exclude
group:
'com.android.tools.external.lombok'
}
android
{
compileSdkVersion
rootProject
.
ext
.
compileSdkVersion
buildToolsVersion
rootProject
.
ext
.
buildToolsVersion
...
...
@@ -45,8 +20,8 @@ android {
applicationId
"chat.rocket.android"
minSdkVersion
16
targetSdkVersion
rootProject
.
ext
.
targetSdkVersion
versionCode
4
4
versionName
"1.0.
22
"
versionCode
5
4
versionName
"1.0.
31
"
testInstrumentationRunner
"android.support.test.runner.AndroidJUnitRunner"
vectorDrawables
.
useSupportLibrary
=
true
multiDexEnabled
true
...
...
@@ -108,6 +83,13 @@ android {
androidTest
.
java
.
srcDirs
+=
'src/androidTest/kotlin'
}
}
dexOptions
{
if
(
System
.
getenv
()[
"CIRCLECI"
]
as
boolean
)
{
javaMaxHeapSize
"1536M"
preDexLibraries
false
}
}
}
play
{
...
...
@@ -115,7 +97,7 @@ play {
track
=
"${track}"
}
ext
{
playLibVersion
=
'11.
0.4
'
playLibVersion
=
'11.
6.0
'
stethoVersion
=
'1.5.0'
stethoOkhttp3Version
=
'1.5.0'
stethoRealmVersion
=
'2.1.0'
...
...
@@ -132,47 +114,37 @@ dependencies {
compile
extraDependencies
.
okHTTP
compile
extraDependencies
.
rxJava
compile
extraDependencies
.
boltTask
compile
supportDependencies
.
multidex
compile
supportDependencies
.
designSupportLibrary
compile
supportDependencies
.
annotation
compile
supportDependencies
.
kotlin
;
compile
rxbindingDependencies
.
rxBinding
compile
rxbindingDependencies
.
rxBindingSupport
compile
rxbindingDependencies
.
rxBindingAppcompact
compile
'com.android.support:multidex:1.0.1'
compile
"org.jetbrains.kotlin:kotlin-stdlib-jre7:$rootProject.ext.kotlinVersion"
compile
"com.google.firebase:firebase-core:$playLibVersion"
compile
"com.google.firebase:firebase-crash:$playLibVersion"
compile
"com.google.android.gms:play-services-gcm:$playLibVersion"
debugCompile
"com.facebook.stetho:stetho:$stethoVersion"
debugCompile
"com.facebook.stetho:stetho-okhttp3:$stethoOkhttp3Version"
debugCompile
"com.uphyca:stetho_realm:$stethoRealmVersion"
compile
"com.trello.rxlifecycle2:rxlifecycle:$rxlifecycleVersion"
compile
"com.trello.rxlifecycle2:rxlifecycle-android:$rxlifecycleVersion"
compile
"com.trello.rxlifecycle2:rxlifecycle-components:$rxlifecycleVersion"
compile
'nl.littlerobots.rxlint:rxlint:1.2'
compile
"frankiesardo:icepick:$icepickVersion"
provided
"frankiesardo:icepick-processor:$icepickVersion"
annotationProcessor
"frankiesardo:icepick-processor:$icepickVersion"
compile
"com.github.hotchemi:permissionsdispatcher:$permissionsdispatcherVersion"
annotationProcessor
"com.github.hotchemi:permissionsdispatcher-processor:$permissionsdispatcherVersion"
compile
(
'com.crashlytics.sdk.android:crashlytics:2.6.8@aar'
)
{
transitive
=
true
;
}
debugCompile
"com.facebook.stetho:stetho:$stethoVersion"
debugCompile
"com.facebook.stetho:stetho-okhttp3:$stethoOkhttp3Version"
debugCompile
"com.uphyca:stetho_realm:$stethoRealmVersion"
debugCompile
"com.tspoon.traceur:traceur:1.0.1"
compile
'com.aurelhubert:ahbottomnavigation:2.0.6'
compile
(
'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.10.6@aar'
)
{
transitive
=
true
}
compile
'com.github.JakeWharton:ViewPagerIndicator:2.4.1@aar'
compile
'com.jakewharton:butterknife:8.5.1'
annotationProcessor
'com.jakewharton:butterknife-compiler:8.5.1'
compile
'com.jakewharton.timber:timber:4.5.1'
compile
'com.github.matrixxun:MaterialBadgeTextView:c5a27e8243'
compile
'com.github.chrisbanes:PhotoView:2.0.0'
provided
'io.reactivex:rxjava:1.3.0'
provided
"com.github.akarnokd:rxjava2-interop:0.10.2"
provided
'com.hadisatrio:Optional:v1.0.1'
testCompile
'junit:junit:4.12'
testCompile
"org.mockito:mockito-core:2.7.19"
testCompile
'org.robolectric:robolectric:3.3'
testCompile
"org.jetbrains.kotlin:kotlin-test:$rootProject.ext.kotlinVersion"
testCompile
"org.jetbrains.kotlin:kotlin-test-junit:$rootProject.ext.kotlinVersion"
testCompile
"org.jetbrains.kotlin:kotlin-reflect:$rootProject.ext.kotlinVersion"
testCompile
"com.nhaarman:mockito-kotlin:1.5.0"
testCompile
'org.amshove.kluent:kluent:1.14'
}
apply
plugin:
'com.google.gms.google-services'
app/src/debug/java/chat/rocket/android/RocketChatApplicationDebug.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
;
import
android.os.StrictMode
;
import
com.facebook.stetho.Stetho
;
import
com.tspoon.traceur.Traceur
;
import
com.uphyca.stetho_realm.RealmInspectorModulesProvider
;
...
...
app/src/debug/java/chat/rocket/android/helper/OkHttpHelper.kt
View file @
5bbd3f7f
...
...
@@ -5,8 +5,8 @@ import chat.rocket.android.RocketChatCache
import
chat.rocket.android.api.rest.CookieInterceptor
import
chat.rocket.android.api.rest.DefaultCookieProvider
import
com.facebook.stetho.okhttp3.StethoInterceptor
import
java.util.concurrent.TimeUnit
import
okhttp3.OkHttpClient
import
java.util.concurrent.TimeUnit
object
OkHttpHelper
{
...
...
app/src/main/AndroidManifest.xml
View file @
5bbd3f7f
...
...
@@ -5,6 +5,7 @@
<uses-permission
android:name=
"android.permission.ACCESS_NETWORK_STATE"
/>
<uses-permission
android:name=
"android.permission.READ_EXTERNAL_STORAGE"
/>
<uses-permission
android:name=
"android.permission.WAKE_LOCK"
/>
<uses-permission
android:name=
"android.permission.VIBRATE"
/>
<permission
android:name=
"chat.rocket.android.permission.C2D_MESSAGE"
...
...
@@ -56,10 +57,32 @@
android:permission=
"com.google.android.c2dm.permission.SEND"
>
<intent-filter>
<action
android:name=
"com.google.android.c2dm.intent.RECEIVE"
/>
<category
android:name=
"com.example.gcm"
/>
<action
android:name=
"com.google.android.c2dm.intent.REGISTRATION"
/>
<category
android:name=
"chat.rocket.android"
/>
</intent-filter>
</receiver>
<receiver
android:name=
"com.google.firebase.iid.FirebaseInstanceIdReceiver"
android:exported=
"true"
android:permission=
"com.google.android.c2dm.permission.SEND"
>
<intent-filter>
<action
android:name=
"com.google.android.c2dm.intent.RECEIVE"
/>
<category
android:name=
"chat.rocket.android"
/>
</intent-filter>
</receiver>
<receiver
android:name=
"com.google.firebase.iid.FirebaseInstanceIdInternalReceiver"
android:exported=
"false"
/>
<service
android:name=
"com.google.firebase.iid.FirebaseInstanceIdService"
android:exported=
"true"
>
<intent-filter
android:priority=
"-500"
>
<action
android:name=
"com.google.firebase.INSTANCE_ID_EVENT"
/>
</intent-filter>
</service>
<service
android:name=
".push.gcm.GCMIntentService"
android:exported=
"false"
>
...
...
@@ -76,6 +99,12 @@
</intent-filter>
</service>
<receiver
android:name=
".push.PushManager$DeleteReceiver"
android:exported=
"false"
/>
<receiver
android:name=
".push.PushManager$ReplyReceiver"
android:exported=
"false"
/>
<meta-data
android:name=
"io.fabric.ApiKey"
android:value=
"12ac6e94f850aaffcdff52001af77ca415d06a43"
/>
...
...
app/src/main/java/chat/rocket/android/RocketChatApplication.java
View file @
5bbd3f7f
...
...
@@ -4,46 +4,62 @@ import android.os.Build;
import
android.support.multidex.MultiDexApplication
;
import
android.support.v7.app.AppCompatDelegate
;
import
chat.rocket.android.helper.OkHttpHelper
;
import
com.crashlytics.android.Crashlytics
;
import
io.fabric.sdk.android.Fabric
;
import
java.util.List
;
import
chat.rocket.persistence.realm.RealmStore
;
import
chat.rocket.android.helper.Logger
;
import
chat.rocket.android.helper.OkHttpHelper
;
import
chat.rocket.android.service.ConnectivityManager
;
import
chat.rocket.core.models.ServerInfo
;
import
chat.rocket.android.widget.RocketChatWidgets
;
import
chat.rocket.android_ddp.DDPClient
;
import
chat.rocket.core.models.ServerInfo
;
import
chat.rocket.persistence.realm.RealmStore
;
import
chat.rocket.persistence.realm.RocketChatPersistenceRealm
;
import
io.fabric.sdk.android.Fabric
;
import
io.reactivex.exceptions.UndeliverableException
;
import
io.reactivex.plugins.RxJavaPlugins
;
/**
* Customized Application-class for Rocket.Chat
*/
public
class
RocketChatApplication
extends
MultiDexApplication
{
private
static
RocketChatApplication
instance
;
private
static
RocketChatApplication
instance
;
public
static
RocketChatApplication
getInstance
()
{
return
instance
;
}
public
static
RocketChatApplication
getInstance
()
{
return
instance
;
}
@Override
public
void
onCreate
()
{
super
.
onCreate
();
Fabric
.
with
(
this
,
new
Crashlytics
());
@Override
public
void
onCreate
()
{
super
.
onCreate
();
DDPClient
.
initialize
(
OkHttpHelper
.
INSTANCE
.
getClientForWebSocket
());
Fabric
.
with
(
this
,
new
Crashlytics
());
RocketChatPersistenceRealm
.
init
(
this
);
RocketChatPersistenceRealm
.
init
(
this
);
List
<
ServerInfo
>
serverInfoList
=
ConnectivityManager
.
getInstance
(
this
).
getServerList
();
for
(
ServerInfo
serverInfo
:
serverInfoList
)
{
RealmStore
.
put
(
serverInfo
.
getHostname
());
}
List
<
ServerInfo
>
serverInfoList
=
ConnectivityManager
.
getInstance
(
this
).
getServerList
();
for
(
ServerInfo
serverInfo
:
serverInfoList
)
{
RealmStore
.
put
(
serverInfo
.
getHostname
());
}
RocketChatWidgets
.
initialize
(
this
,
OkHttpHelper
.
INSTANCE
.
getClientForDownloadFile
(
this
));
RocketChatWidgets
.
initialize
(
this
,
OkHttpHelper
.
INSTANCE
.
getClientForDownloadFile
(
this
));
if
(
Build
.
VERSION
.
SDK_INT
<
Build
.
VERSION_CODES
.
LOLLIPOP
)
{
AppCompatDelegate
.
setCompatVectorFromResourcesEnabled
(
true
);
}
if
(
Build
.
VERSION
.
SDK_INT
<
Build
.
VERSION_CODES
.
LOLLIPOP
)
{
AppCompatDelegate
.
setCompatVectorFromResourcesEnabled
(
true
);
}
RxJavaPlugins
.
setErrorHandler
(
e
->
{
if
(
e
instanceof
UndeliverableException
)
{
e
=
e
.
getCause
();
}
if
(
BuildConfig
.
DEBUG
)
{
e
.
printStackTrace
();
}
Logger
.
report
(
e
);
});
instance
=
this
;
}
instance
=
this
;
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/RocketChatCache.java
View file @
5bbd3f7f
...
...
@@ -22,12 +22,15 @@ import io.reactivex.BackpressureStrategy;
import
io.reactivex.Flowable
;
import
io.reactivex.annotations.NonNull
;
import
io.reactivex.annotations.Nullable
;
import
okhttp3.HttpUrl
;
/**
* sharedpreference-based cache.
*/
public
class
RocketChatCache
{
private
static
final
String
KEY_SELECTED_SERVER_HOSTNAME
=
"KEY_SELECTED_SERVER_HOSTNAME"
;
private
static
final
String
KEY_SELECTED_SITE_URL
=
"KEY_SELECTED_SITE_URL"
;
private
static
final
String
KEY_SELECTED_SITE_NAME
=
"KEY_SELECTED_SITE_NAME"
;
private
static
final
String
KEY_SELECTED_ROOM_ID
=
"KEY_SELECTED_ROOM_ID"
;
private
static
final
String
KEY_PUSH_ID
=
"KEY_PUSH_ID"
;
private
static
final
String
KEY_HOSTNAME_LIST
=
"KEY_HOSTNAME_LIST"
;
...
...
@@ -50,6 +53,75 @@ public class RocketChatCache {
setString
(
KEY_SELECTED_SERVER_HOSTNAME
,
newHostname
);
}
public
void
addHostSiteName
(
@NonNull
String
currentHostname
,
@NonNull
String
siteName
)
{
try
{
String
hostSiteNamesJson
=
getHostSiteNamesJson
();
JSONObject
jsonObject
=
(
hostSiteNamesJson
==
null
)
?
new
JSONObject
()
:
new
JSONObject
(
hostSiteNamesJson
);
jsonObject
.
put
(
currentHostname
,
siteName
);
setString
(
KEY_SELECTED_SITE_NAME
,
jsonObject
.
toString
());
}
catch
(
JSONException
e
)
{
RCLog
.
e
(
e
);
}
}
public
@NonNull
String
getHostSiteName
(
@NonNull
String
host
)
{
if
(
host
.
startsWith
(
"http"
))
{
HttpUrl
url
=
HttpUrl
.
parse
(
host
);
if
(
url
!=
null
)
{
host
=
url
.
host
();
}
}
try
{
String
hostSiteNamesJson
=
getHostSiteNamesJson
();
JSONObject
jsonObject
=
(
hostSiteNamesJson
==
null
)
?
new
JSONObject
()
:
new
JSONObject
(
hostSiteNamesJson
);
host
=
getSiteUrlFor
(
host
);
return
jsonObject
.
optString
(
host
);
}
catch
(
JSONException
e
)
{
RCLog
.
e
(
e
);
}
return
""
;
}
private
@Nullable
String
getHostSiteNamesJson
()
{
return
getString
(
KEY_SELECTED_SITE_NAME
,
null
);
}
public
void
addHostnameSiteUrl
(
@Nullable
String
hostnameAlias
,
@NonNull
String
currentHostname
)
{
String
alias
=
null
;
if
(
hostnameAlias
!=
null
)
{
alias
=
hostnameAlias
.
toLowerCase
();
}
try
{
String
selectedHostnameAliasJson
=
getLoginHostnamesJson
();
JSONObject
jsonObject
=
selectedHostnameAliasJson
==
null
?
new
JSONObject
()
:
new
JSONObject
(
selectedHostnameAliasJson
);
jsonObject
.
put
(
alias
,
currentHostname
);
setString
(
KEY_SELECTED_SITE_URL
,
jsonObject
.
toString
());
}
catch
(
JSONException
e
)
{
RCLog
.
e
(
e
);
}
}
public
@Nullable
String
getSiteUrlFor
(
String
hostname
)
{
try
{
String
selectedServerHostname
=
getSelectedServerHostname
();
if
(
getLoginHostnamesJson
()
==
null
||
getLoginHostnamesJson
().
isEmpty
())
{
return
null
;
}
return
new
JSONObject
(
getLoginHostnamesJson
())
.
optString
(
hostname
,
selectedServerHostname
);
}
catch
(
JSONException
e
)
{
RCLog
.
e
(
e
);
}
return
null
;
}
private
@Nullable
String
getLoginHostnamesJson
()
{
return
getString
(
KEY_SELECTED_SITE_URL
,
null
);
}
public
void
addHostname
(
@NonNull
String
hostname
,
@Nullable
String
hostnameAvatarUri
,
String
siteName
)
{
String
hostnameList
=
getString
(
KEY_HOSTNAME_LIST
,
null
);
try
{
...
...
app/src/main/java/chat/rocket/android/activity/AbstractAuthedActivity.java
View file @
5bbd3f7f
...
...
@@ -3,21 +3,25 @@ package chat.rocket.android.activity;
import
android.content.Intent
;
import
android.os.Bundle
;
import
android.support.annotation.Nullable
;
import
com.hadisatrio.optional.Optional
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.reactivex.disposables.CompositeDisposable
;
import
io.reactivex.schedulers.Schedulers
;
import
java.util.List
;
import
chat.rocket.android.LaunchUtil
;
import
chat.rocket.android.R
;
import
chat.rocket.android.RocketChatCache
;
import
chat.rocket.android.helper.Logger
;
import
chat.rocket.android.push.PushConstants
;
import
chat.rocket.android.push.PushNotificationHandler
;
import
chat.rocket.android.push.PushManager
;
import
chat.rocket.android.service.ConnectivityManager
;
import
chat.rocket.core.models.ServerInfo
;
import
chat.rocket.persistence.realm.RealmStore
;
import
chat.rocket.persistence.realm.models.ddp.RealmRoom
;
import
icepick.State
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.reactivex.disposables.CompositeDisposable
;
import
io.reactivex.schedulers.Schedulers
;
import
okhttp3.HttpUrl
;
abstract
class
AbstractAuthedActivity
extends
AbstractFragmentActivity
{
@State
protected
String
hostname
;
...
...
@@ -39,7 +43,6 @@ abstract class AbstractAuthedActivity extends AbstractFragmentActivity {
}
updateHostnameIfNeeded
(
rocketChatCache
.
getSelectedServerHostname
());
updateRoomIdIfNeeded
(
rocketChatCache
.
getSelectedRoomId
());
}
@Override
...
...
@@ -53,20 +56,36 @@ abstract class AbstractAuthedActivity extends AbstractFragmentActivity {
return
;
}
if
(
intent
.
hasExtra
(
PushConstants
.
HOSTNAME
))
{
rocketChatCache
.
setSelectedServerHostname
(
intent
.
getStringExtra
(
PushConstants
.
HOSTNAME
));
if
(
intent
.
hasExtra
(
PushConstants
.
ROOM_ID
))
{
rocketChatCache
.
setSelectedRoomId
(
intent
.
getStringExtra
(
PushConstants
.
ROOM_ID
));
if
(
intent
.
hasExtra
(
PushManager
.
EXTRA_HOSTNAME
))
{
String
hostname
=
intent
.
getStringExtra
(
PushManager
.
EXTRA_HOSTNAME
);
HttpUrl
url
=
HttpUrl
.
parse
(
hostname
);
if
(
url
!=
null
)
{
String
hostnameFromPush
=
url
.
host
();
String
loginHostname
=
rocketChatCache
.
getSiteUrlFor
(
hostnameFromPush
);
rocketChatCache
.
setSelectedServerHostname
(
loginHostname
);
if
(
intent
.
hasExtra
(
PushManager
.
EXTRA_ROOM_ID
))
{
rocketChatCache
.
setSelectedRoomId
(
intent
.
getStringExtra
(
PushManager
.
EXTRA_ROOM_ID
));
}
}
PushManager
.
INSTANCE
.
clearNotificationsByHost
(
hostname
);
}
else
{
updateHostnameIfNeeded
(
rocketChatCache
.
getSelectedServerHostname
());
}
if
(
intent
.
hasExtra
(
Push
Constants
.
NOT_ID
))
{
if
(
intent
.
hasExtra
(
Push
Manager
.
EXTRA_NOT_ID
)
&&
intent
.
hasExtra
(
PushManager
.
EXTRA_HOSTNAME
))
{
isNotification
=
true
;
PushNotificationHandler
.
cleanUpNotificationStack
(
intent
.
getIntExtra
(
PushConstants
.
NOT_ID
,
0
));
int
notificationId
=
intent
.
getIntExtra
(
PushManager
.
EXTRA_NOT_ID
,
0
);
String
hostname
=
intent
.
getStringExtra
(
PushManager
.
EXTRA_HOSTNAME
);
HttpUrl
url
=
HttpUrl
.
parse
(
hostname
);
if
(
url
!=
null
)
{
String
hostnameFromPush
=
url
.
host
();
String
loginHostname
=
rocketChatCache
.
getSiteUrlFor
(
hostnameFromPush
);
PushManager
.
INSTANCE
.
clearNotificationsByHostAndNotificationId
(
loginHostname
,
notificationId
);
}
else
{
PushManager
.
INSTANCE
.
clearNotificationsByNotificationId
(
notificationId
);
}
}
}
...
...
@@ -74,17 +93,22 @@ abstract class AbstractAuthedActivity extends AbstractFragmentActivity {
if
(
hostname
==
null
)
{
if
(
newHostname
!=
null
&&
assertServerRealmStoreExists
(
newHostname
))
{
updateHostname
(
newHostname
);
updateRoomIdIfNeeded
(
rocketChatCache
.
getSelectedRoomId
());
}
else
{
recoverFromHostnameError
();
}
}
else
{
if
(
hostname
.
equals
(
newHostname
))
{
updateHostname
(
newHostname
);
updateRoomIdIfNeeded
(
rocketChatCache
.
getSelectedRoomId
());
return
;
}
if
(
assertServerRealmStoreExists
(
newHostname
))
{
updateHostname
(
newHostname
);
Intent
intent
=
new
Intent
(
this
,
MainActivity
.
class
);
startActivity
(
intent
);
finish
();
overridePendingTransition
(
R
.
anim
.
slide_in
,
R
.
anim
.
slide_out
);
}
else
{
recoverFromHostnameError
();
}
...
...
app/src/main/java/chat/rocket/android/activity/LoginActivity.java
View file @
5bbd3f7f
...
...
@@ -8,8 +8,8 @@ import android.support.v4.app.Fragment;
import
chat.rocket.android.R
;
import
chat.rocket.android.fragment.server_config.LoginFragment
;
import
chat.rocket.android.fragment.server_config.RetryLoginFragment
;
import
chat.rocket.core.interactors.SessionInteractor
;
import
chat.rocket.android.service.ConnectivityManager
;
import
chat.rocket.core.interactors.SessionInteractor
;
import
chat.rocket.persistence.realm.repositories.RealmSessionRepository
;
/**
...
...
app/src/main/java/chat/rocket/android/activity/LoginPresenter.java
View file @
5bbd3f7f
...
...
@@ -2,14 +2,13 @@ package chat.rocket.android.activity;
import
android.support.annotation.NonNull
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.reactivex.disposables.Disposable
;
import
chat.rocket.android.BackgroundLooper
;
import
chat.rocket.android.helper.Logger
;
import
chat.rocket.android.service.ConnectivityManagerApi
;
import
chat.rocket.android.shared.BasePresenter
;
import
chat.rocket.core.interactors.SessionInteractor
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.reactivex.disposables.Disposable
;
public
class
LoginPresenter
extends
BasePresenter
<
LoginContract
.
View
>
implements
LoginContract
.
Presenter
{
...
...
app/src/main/java/chat/rocket/android/activity/MainActivity.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
activity
;
import
android.content.Intent
;
import
android.graphics.drawable.Drawable
;
import
android.os.Bundle
;
import
android.support.annotation.NonNull
;
import
android.support.annotation.Nullable
;
import
android.support.design.widget.Snackbar
;
import
android.support.v4.app.Fragment
;
...
...
@@ -26,6 +28,7 @@ import chat.rocket.android.fragment.chatroom.RoomFragment;
import
chat.rocket.android.fragment.sidebar.SidebarMainFragment
;
import
chat.rocket.android.helper.KeyboardHelper
;
import
chat.rocket.android.service.ConnectivityManager
;
import
chat.rocket.android.service.ConnectivityManagerApi
;
import
chat.rocket.android.widget.RoomToolbar
;
import
chat.rocket.android.widget.helper.FrescoHelper
;
import
chat.rocket.core.interactors.CanCreateRoomInteractor
;
...
...
@@ -43,314 +46,316 @@ import hugo.weaving.DebugLog;
* Entry-point for Rocket.Chat.Android application.
*/
public
class
MainActivity
extends
AbstractAuthedActivity
implements
MainContract
.
View
{
private
RoomToolbar
toolbar
;
private
StatusTicker
statusTicker
;
private
SlidingPaneLayout
pane
;
private
MainContract
.
Presenter
presenter
;
@Override
public
int
getLayoutContainerForFragment
()
{
return
R
.
id
.
activity_main_container
;
}
@Override
protected
void
onCreate
(
@Nullable
Bundle
savedInstanceState
)
{
super
.
onCreate
(
savedInstanceState
);
setContentView
(
R
.
layout
.
activity_main
);
toolbar
=
(
RoomToolbar
)
findViewById
(
R
.
id
.
activity_main_toolbar
);
statusTicker
=
new
StatusTicker
();
pane
=
(
SlidingPaneLayout
)
findViewById
(
R
.
id
.
sliding_pane
);
setupToolbar
();
}
@Override
protected
void
onResume
()
{
super
.
onResume
();
if
(
hostname
==
null
||
presenter
==
null
)
{
hostname
=
new
RocketChatCache
(
getApplicationContext
()).
getSelectedServerHostname
();
if
(
hostname
==
null
)
{
showAddServerScreen
();
}
else
{
onHostnameUpdated
();
}
}
else
{
presenter
.
bindViewOnly
(
this
);
presenter
.
loadSignedInServers
(
hostname
);
private
RoomToolbar
toolbar
;
private
SlidingPaneLayout
pane
;
private
MainContract
.
Presenter
presenter
;
private
volatile
Snackbar
statusTicker
;
@Override
public
int
getLayoutContainerForFragment
()
{
return
R
.
id
.
activity_main_container
;
}
}
@Override
protected
void
onPause
()
{
if
(
presenter
!=
null
)
{
presenter
.
release
();
@Override
protected
void
onCreate
(
@Nullable
Bundle
savedInstanceState
)
{
super
.
onCreate
(
savedInstanceState
);
setContentView
(
R
.
layout
.
activity_main
);
toolbar
=
findViewById
(
R
.
id
.
activity_main_toolbar
);
pane
=
findViewById
(
R
.
id
.
sliding_pane
);
setupToolbar
();
}
super
.
onPause
();
}
private
void
showAddServerActivity
()
{
closeSidebarIfNeeded
();
Intent
intent
=
new
Intent
(
this
,
AddServerActivity
.
class
);
intent
.
setFlags
(
Intent
.
FLAG_ACTIVITY_REORDER_TO_FRONT
|
Intent
.
FLAG_ACTIVITY_CLEAR_TOP
|
Intent
.
FLAG_ACTIVITY_SINGLE_TOP
);
intent
.
putExtra
(
AddServerActivity
.
EXTRA_FINISH_ON_BACK_PRESS
,
true
);
startActivity
(
intent
);
}
private
void
setupToolbar
()
{
if
(
pane
!=
null
)
{
pane
.
setPanelSlideListener
(
new
SlidingPaneLayout
.
PanelSlideListener
()
{
@Override
public
void
onPanelSlide
(
View
view
,
float
v
)
{
//Ref: ActionBarDrawerToggle#setProgress
toolbar
.
setNavigationIconProgress
(
v
);
@Override
protected
void
onResume
()
{
super
.
onResume
();
ConnectivityManagerApi
connectivityManager
=
ConnectivityManager
.
getInstance
(
getApplicationContext
());
if
(
hostname
==
null
||
presenter
==
null
)
{
String
previousHostname
=
hostname
;
hostname
=
new
RocketChatCache
(
getApplicationContext
()).
getSelectedServerHostname
();
if
(
hostname
==
null
)
{
showAddServerScreen
();
}
else
{
onHostnameUpdated
();
if
(!
hostname
.
equalsIgnoreCase
(
previousHostname
))
{
connectivityManager
.
resetConnectivityStateList
();
connectivityManager
.
keepAliveServer
();
}
}
}
else
{
connectivityManager
.
keepAliveServer
();
presenter
.
bindView
(
this
);
presenter
.
loadSignedInServers
(
hostname
);
roomId
=
new
RocketChatCache
(
getApplicationContext
()).
getSelectedRoomId
();
}
}
@Override
public
void
onPanelOpened
(
View
view
)
{
toolbar
.
setNavigationIconVerticalMirror
(
true
);
@Override
protected
void
onPause
()
{
if
(
presenter
!=
null
)
{
presenter
.
release
();
}
// Dismiss any status ticker
if
(
statusTicker
!=
null
)
statusTicker
.
dismiss
();
@Override
public
void
onPanelClosed
(
View
view
)
{
toolbar
.
setNavigationIconVerticalMirror
(
false
);
Fragment
fragment
=
getSupportFragmentManager
()
.
findFragmentById
(
R
.
id
.
sidebar_fragment_container
);
if
(
fragment
!=
null
&&
fragment
instanceof
SidebarMainFragment
)
{
SidebarMainFragment
sidebarMainFragment
=
(
SidebarMainFragment
)
fragment
;
sidebarMainFragment
.
toggleUserActionContainer
(
false
);
sidebarMainFragment
.
showUserActionContainer
(
false
);
}
}
});
if
(
toolbar
!=
null
)
{
toolbar
.
setNavigationOnClickListener
(
view
->
{
if
(
pane
.
isSlideable
()
&&
!
pane
.
isOpen
())
{
pane
.
openPane
();
}
});
}
super
.
onPause
();
}
}
private
boolean
closeSidebarIfNeeded
()
{
// REMARK: Tablet UI doesn't have SlidingPane!
if
(
pane
!=
null
&&
pane
.
isSlideable
()
&&
pane
.
isOpen
())
{
pane
.
closePane
();
return
true
;
private
void
showAddServerActivity
()
{
closeSidebarIfNeeded
();
Intent
intent
=
new
Intent
(
this
,
AddServerActivity
.
class
);
intent
.
setFlags
(
Intent
.
FLAG_ACTIVITY_REORDER_TO_FRONT
|
Intent
.
FLAG_ACTIVITY_CLEAR_TOP
|
Intent
.
FLAG_ACTIVITY_SINGLE_TOP
);
intent
.
putExtra
(
AddServerActivity
.
EXTRA_FINISH_ON_BACK_PRESS
,
true
);
startActivity
(
intent
);
}
return
false
;
}
@DebugLog
@Override
protected
void
onHostnameUpdated
()
{
super
.
onHostnameUpdated
();
private
void
setupToolbar
()
{
if
(
pane
!=
null
)
{
pane
.
setPanelSlideListener
(
new
SlidingPaneLayout
.
PanelSlideListener
()
{
@Override
public
void
onPanelSlide
(
@NonNull
View
view
,
float
v
)
{
//Ref: ActionBarDrawerToggle#setProgress
toolbar
.
setNavigationIconProgress
(
v
);
}
@Override
public
void
onPanelOpened
(
@NonNull
View
view
)
{
toolbar
.
setNavigationIconVerticalMirror
(
true
);
}
@Override
public
void
onPanelClosed
(
@NonNull
View
view
)
{
toolbar
.
setNavigationIconVerticalMirror
(
false
);
Fragment
fragment
=
getSupportFragmentManager
()
.
findFragmentById
(
R
.
id
.
sidebar_fragment_container
);
if
(
fragment
!=
null
&&
fragment
instanceof
SidebarMainFragment
)
{
SidebarMainFragment
sidebarMainFragment
=
(
SidebarMainFragment
)
fragment
;
sidebarMainFragment
.
toggleUserActionContainer
(
false
);
sidebarMainFragment
.
showUserActionContainer
(
false
);
}
}
});
if
(
toolbar
!=
null
)
{
toolbar
.
setNavigationOnClickListener
(
view
->
{
if
(
pane
.
isSlideable
()
&&
!
pane
.
isOpen
())
{
pane
.
openPane
();
}
});
}
}
closeSidebarIfNeeded
();
}
if
(
presenter
!=
null
)
{
presenter
.
release
();
private
boolean
closeSidebarIfNeeded
()
{
// REMARK: Tablet UI doesn't have SlidingPane!
if
(
pane
!=
null
&&
pane
.
isSlideable
()
&&
pane
.
isOpen
())
{
pane
.
closePane
();
return
true
;
}
return
false
;
}
RoomInteractor
roomInteractor
=
new
RoomInteractor
(
new
RealmRoomRepository
(
hostname
));
@DebugLog
@Override
protected
void
onHostnameUpdated
()
{
super
.
onHostnameUpdated
();
CanCreateRoomInteractor
createRoomInteractor
=
new
CanCreateRoomInteractor
(
new
RealmUserRepository
(
hostname
),
new
SessionInteractor
(
new
RealmSessionRepository
(
hostname
))
);
if
(
presenter
!=
null
)
{
presenter
.
release
();
}
RoomInteractor
roomInteractor
=
new
RoomInteractor
(
new
RealmRoomRepository
(
hostname
));
SessionInteractor
sessionInteractor
=
new
SessionInteractor
(
new
RealmSessionRepository
(
hostname
)
);
CanCreateRoomInteractor
createRoomInteractor
=
new
CanCreateRoomInteractor
(
new
RealmUserRepository
(
hostname
),
new
SessionInteractor
(
new
RealmSessionRepository
(
hostname
))
);
PublicSettingRepository
publicSettingRepository
=
new
RealmPublicSettingRepository
(
hostname
);
SessionInteractor
sessionInteractor
=
new
SessionInteractor
(
new
RealmSessionRepository
(
hostname
)
);
RocketChatCache
rocketChatCache
=
new
RocketChatCache
(
this
);
PublicSettingRepository
publicSettingRepository
=
new
RealmPublicSettingRepository
(
hostname
);
presenter
=
new
MainPresenter
(
roomInteractor
,
createRoomInteractor
,
sessionInteractor
,
new
MethodCallHelper
(
this
,
hostname
),
ConnectivityManager
.
getInstance
(
getApplicationContext
()),
rocketChatCache
,
publicSettingRepository
);
RocketChatCache
rocketChatCache
=
new
RocketChatCache
(
this
);
updateSidebarMainFragment
();
presenter
=
new
MainPresenter
(
roomInteractor
,
createRoomInteractor
,
sessionInteractor
,
new
MethodCallHelper
(
this
,
hostname
),
ConnectivityManager
.
getInstance
(
getApplicationContext
()),
rocketChatCache
,
publicSettingRepository
);
presenter
.
bindView
(
this
);
presenter
.
loadSignedInServers
(
hostname
);
updateSidebarMainFragment
();
roomId
=
rocketChatCache
.
getSelectedRoomId
(
);
}
presenter
.
bindView
(
this
);
presenter
.
loadSignedInServers
(
hostname
);
private
void
updateSidebarMainFragment
()
{
closeSidebarIfNeeded
();
String
selectedServerHostname
=
new
RocketChatCache
(
this
).
getSelectedServerHostname
();
Fragment
sidebarFragment
=
findFragmentByTag
(
selectedServerHostname
);
if
(
sidebarFragment
==
null
)
{
sidebarFragment
=
SidebarMainFragment
.
create
(
selectedServerHostname
);
roomId
=
rocketChatCache
.
getSelectedRoomId
();
}
getSupportFragmentManager
().
beginTransaction
()
.
replace
(
R
.
id
.
sidebar_fragment_container
,
sidebarFragment
,
selectedServerHostname
)
.
commit
();
getSupportFragmentManager
().
executePendingTransactions
();
}
@Override
protected
void
onRoomIdUpdated
()
{
super
.
onRoomIdUpdated
();
presenter
.
onOpenRoom
(
hostname
,
roomId
);
}
@Override
protected
boolean
onBackPress
()
{
return
closeSidebarIfNeeded
()
||
super
.
onBackPress
();
}
@Override
public
void
showHome
()
{
showFragment
(
new
HomeFragment
());
}
@Override
public
void
showRoom
(
String
hostname
,
String
roomId
)
{
showFragment
(
RoomFragment
.
create
(
hostname
,
roomId
));
closeSidebarIfNeeded
();
KeyboardHelper
.
hideSoftKeyboard
(
this
);
}
@Override
public
void
showUnreadCount
(
long
roomsCount
,
int
mentionsCount
)
{
toolbar
.
setUnreadBadge
((
int
)
roomsCount
,
mentionsCount
);
}
@Override
public
void
showAddServerScreen
()
{
LaunchUtil
.
showAddServerActivity
(
this
);
}
@Override
public
void
showLoginScreen
()
{
LaunchUtil
.
showLoginActivity
(
this
,
hostname
);
statusTicker
.
updateStatus
(
StatusTicker
.
STATUS_DISMISS
,
null
);
}
@Override
public
void
showConnectionError
()
{
statusTicker
.
updateStatus
(
StatusTicker
.
STATUS_CONNECTION_ERROR
,
Snackbar
.
make
(
findViewById
(
getLayoutContainerForFragment
()),
R
.
string
.
fragment_retry_login_error_title
,
Snackbar
.
LENGTH_INDEFINITE
)
.
setAction
(
R
.
string
.
fragment_retry_login_retry_title
,
view
->
presenter
.
onRetryLogin
()));
}
@Override
public
void
showConnecting
()
{
statusTicker
.
updateStatus
(
StatusTicker
.
STATUS_TOKEN_LOGIN
,
Snackbar
.
make
(
findViewById
(
getLayoutContainerForFragment
()),
R
.
string
.
server_config_activity_authenticating
,
Snackbar
.
LENGTH_INDEFINITE
));
}
@Override
public
void
showConnectionOk
()
{
statusTicker
.
updateStatus
(
StatusTicker
.
STATUS_DISMISS
,
null
);
}
@Override
public
void
showSignedInServers
(
List
<
Pair
<
String
,
Pair
<
String
,
String
>>>
serverList
)
{
final
SlidingPaneLayout
subPane
=
(
SlidingPaneLayout
)
findViewById
(
R
.
id
.
sub_sliding_pane
);
if
(
subPane
!=
null
)
{
LinearLayout
serverListContainer
=
subPane
.
findViewById
(
R
.
id
.
server_list_bar
);
View
addServerButton
=
subPane
.
findViewById
(
R
.
id
.
btn_add_server
);
addServerButton
.
setOnClickListener
(
view
->
showAddServerActivity
());
serverListContainer
.
removeAllViews
();
for
(
Pair
<
String
,
Pair
<
String
,
String
>>
server
:
serverList
)
{
String
serverHostname
=
server
.
first
;
Pair
<
String
,
String
>
serverInfoPair
=
server
.
second
;
String
logoUrl
=
serverInfoPair
.
first
;
String
siteName
=
serverInfoPair
.
second
;
View
serverView
=
serverListContainer
.
findViewWithTag
(
serverHostname
);
if
(
serverView
==
null
)
{
View
newServerView
=
LayoutInflater
.
from
(
this
).
inflate
(
R
.
layout
.
server_row
,
serverListContainer
,
false
);
SimpleDraweeView
serverButton
=
newServerView
.
findViewById
(
R
.
id
.
drawee_server_button
);
TextView
hostnameLabel
=
newServerView
.
findViewById
(
R
.
id
.
text_view_server_label
);
TextView
siteNameLabel
=
newServerView
.
findViewById
(
R
.
id
.
text_view_site_name_label
);
ImageView
dotView
=
newServerView
.
findViewById
(
R
.
id
.
selected_server_dot
);
newServerView
.
setTag
(
serverHostname
);
hostnameLabel
.
setText
(
serverHostname
);
siteNameLabel
.
setText
(
siteName
);
// Currently selected server
if
(
hostname
.
equalsIgnoreCase
(
serverHostname
))
{
newServerView
.
setSelected
(
true
);
dotView
.
setVisibility
(
View
.
VISIBLE
);
}
else
{
newServerView
.
setSelected
(
false
);
dotView
.
setVisibility
(
View
.
GONE
);
}
newServerView
.
setOnClickListener
(
view
->
changeServerIfNeeded
(
serverHostname
));
FrescoHelper
.
INSTANCE
.
loadImage
(
serverButton
,
logoUrl
,
ContextCompat
.
getDrawable
(
this
,
R
.
mipmap
.
ic_launcher
));
serverListContainer
.
addView
(
newServerView
);
private
void
updateSidebarMainFragment
()
{
closeSidebarIfNeeded
();
String
selectedServerHostname
=
new
RocketChatCache
(
this
).
getSelectedServerHostname
();
Fragment
sidebarFragment
=
findFragmentByTag
(
selectedServerHostname
);
if
(
sidebarFragment
==
null
)
{
sidebarFragment
=
SidebarMainFragment
.
create
(
selectedServerHostname
);
}
}
serverListContainer
.
addView
(
addServerButton
);
getSupportFragmentManager
().
beginTransaction
()
.
replace
(
R
.
id
.
sidebar_fragment_container
,
sidebarFragment
,
selectedServerHostname
)
.
commit
();
getSupportFragmentManager
().
executePendingTransactions
();
}
@Override
protected
void
onRoomIdUpdated
()
{
super
.
onRoomIdUpdated
();
presenter
.
onOpenRoom
(
hostname
,
roomId
);
}
@Override
protected
boolean
onBackPress
()
{
return
closeSidebarIfNeeded
()
||
super
.
onBackPress
();
}
@Override
public
void
showHome
()
{
showFragment
(
new
HomeFragment
());
}
@Override
public
void
showRoom
(
String
hostname
,
String
roomId
)
{
showFragment
(
RoomFragment
.
create
(
hostname
,
roomId
));
closeSidebarIfNeeded
();
KeyboardHelper
.
hideSoftKeyboard
(
this
);
}
@Override
public
void
showUnreadCount
(
long
roomsCount
,
int
mentionsCount
)
{
toolbar
.
setUnreadBadge
((
int
)
roomsCount
,
mentionsCount
);
}
}
private
void
changeServerIfNeeded
(
String
serverHostname
)
{
if
(!
hostname
.
equalsIgnoreCase
(
serverHostname
))
{
RocketChatCache
rocketChatCache
=
new
RocketChatCache
(
getApplicationContext
());
rocketChatCache
.
setSelectedServerHostname
(
serverHostname
);
@Override
public
void
showAddServerScreen
()
{
LaunchUtil
.
showAddServerActivity
(
this
);
}
}
@DebugLog
public
void
onLogout
()
{
if
(
new
RocketChatCache
(
getApplicationContext
()).
getSelectedServerHostname
()
==
null
)
{
LaunchUtil
.
showMainActivity
(
this
);
}
else
{
onHostnameUpdated
();
@Override
public
void
showLoginScreen
()
{
LaunchUtil
.
showLoginActivity
(
this
,
hostname
);
showConnectionOk
();
}
}
@DebugLog
public
void
beforeLogoutCleanUp
()
{
presenter
.
beforeLogoutCleanUp
();
}
@Override
public
synchronized
void
showConnectionError
()
{
dismissStatusTickerIfShowing
();
statusTicker
=
Snackbar
.
make
(
findViewById
(
getLayoutContainerForFragment
()),
R
.
string
.
fragment_retry_login_error_title
,
Snackbar
.
LENGTH_INDEFINITE
)
.
setAction
(
R
.
string
.
fragment_retry_login_retry_title
,
view
->
ConnectivityManager
.
getInstance
(
getApplicationContext
()).
keepAliveServer
());
statusTicker
.
show
();
}
//TODO: consider this class to define in layouthelper for more complicated operation.
private
static
class
StatusTicker
{
public
static
final
int
STATUS_DISMISS
=
0
;
public
static
final
int
STATUS_CONNECTION_ERROR
=
1
;
public
static
final
int
STATUS_TOKEN_LOGIN
=
2
;
public
static
final
int
STATUS_LOGGING_OUT
=
3
;
@Override
public
synchronized
void
showConnecting
()
{
dismissStatusTickerIfShowing
();
statusTicker
=
Snackbar
.
make
(
findViewById
(
getLayoutContainerForFragment
()),
R
.
string
.
server_config_activity_authenticating
,
Snackbar
.
LENGTH_INDEFINITE
);
statusTicker
.
show
();
}
private
int
status
;
private
Snackbar
snackbar
;
@Override
public
synchronized
void
showConnectionOk
()
{
dismissStatusTickerIfShowing
();
}
public
StatusTicker
()
{
status
=
STATUS_DISMISS
;
private
void
dismissStatusTickerIfShowing
()
{
if
(
statusTicker
!=
null
)
{
statusTicker
.
dismiss
();
}
}
@Override
public
void
showSignedInServers
(
List
<
Pair
<
String
,
Pair
<
String
,
String
>>>
serverList
)
{
final
SlidingPaneLayout
subPane
=
findViewById
(
R
.
id
.
sub_sliding_pane
);
if
(
subPane
!=
null
)
{
LinearLayout
serverListContainer
=
subPane
.
findViewById
(
R
.
id
.
server_list_bar
);
View
addServerButton
=
subPane
.
findViewById
(
R
.
id
.
btn_add_server
);
addServerButton
.
setOnClickListener
(
view
->
showAddServerActivity
());
serverListContainer
.
removeAllViews
();
for
(
Pair
<
String
,
Pair
<
String
,
String
>>
server
:
serverList
)
{
String
serverHostname
=
server
.
first
;
Pair
<
String
,
String
>
serverInfoPair
=
server
.
second
;
String
logoUrl
=
serverInfoPair
.
first
;
String
siteName
=
serverInfoPair
.
second
;
View
serverView
=
serverListContainer
.
findViewWithTag
(
serverHostname
);
if
(
serverView
==
null
)
{
View
newServerView
=
LayoutInflater
.
from
(
this
).
inflate
(
R
.
layout
.
server_row
,
serverListContainer
,
false
);
SimpleDraweeView
serverButton
=
newServerView
.
findViewById
(
R
.
id
.
drawee_server_button
);
TextView
hostnameLabel
=
newServerView
.
findViewById
(
R
.
id
.
text_view_server_label
);
TextView
siteNameLabel
=
newServerView
.
findViewById
(
R
.
id
.
text_view_site_name_label
);
ImageView
dotView
=
newServerView
.
findViewById
(
R
.
id
.
selected_server_dot
);
newServerView
.
setTag
(
serverHostname
);
hostnameLabel
.
setText
(
serverHostname
);
siteNameLabel
.
setText
(
siteName
);
// Currently selected server
if
(
hostname
.
equalsIgnoreCase
(
serverHostname
))
{
newServerView
.
setSelected
(
true
);
dotView
.
setVisibility
(
View
.
VISIBLE
);
}
else
{
newServerView
.
setSelected
(
false
);
dotView
.
setVisibility
(
View
.
GONE
);
}
newServerView
.
setOnClickListener
(
view
->
changeServerIfNeeded
(
serverHostname
));
Drawable
drawable
=
ContextCompat
.
getDrawable
(
this
,
R
.
mipmap
.
ic_launcher
);
if
(
drawable
==
null
)
{
int
id
=
getResources
().
getIdentifier
(
"rocket_chat_notification"
,
"drawable"
,
getPackageName
());
drawable
=
ContextCompat
.
getDrawable
(
this
,
id
);
}
FrescoHelper
.
INSTANCE
.
loadImage
(
serverButton
,
logoUrl
,
drawable
);
serverListContainer
.
addView
(
newServerView
);
}
}
serverListContainer
.
addView
(
addServerButton
);
}
}
public
void
updateStatus
(
int
status
,
Snackbar
snackbar
)
{
if
(
status
==
this
.
status
)
{
return
;
}
this
.
status
=
status
;
if
(
this
.
snackbar
!=
null
)
{
this
.
snackbar
.
dismiss
();
}
if
(
status
!=
STATUS_DISMISS
)
{
this
.
snackbar
=
snackbar
;
if
(
this
.
snackbar
!=
null
)
{
this
.
snackbar
.
show
();
@Override
public
void
refreshRoom
()
{
Fragment
fragment
=
getSupportFragmentManager
().
findFragmentById
(
getLayoutContainerForFragment
());
if
(
fragment
!=
null
&&
fragment
instanceof
RoomFragment
)
{
RoomFragment
roomFragment
=
(
RoomFragment
)
fragment
;
roomFragment
.
loadMessages
();
}
}
}
}
private
void
changeServerIfNeeded
(
String
serverHostname
)
{
if
(!
hostname
.
equalsIgnoreCase
(
serverHostname
))
{
RocketChatCache
rocketChatCache
=
new
RocketChatCache
(
getApplicationContext
());
rocketChatCache
.
setSelectedServerHostname
(
serverHostname
);
}
}
@DebugLog
public
void
onLogout
()
{
if
(
new
RocketChatCache
(
getApplicationContext
()).
getSelectedServerHostname
()
==
null
)
{
LaunchUtil
.
showMainActivity
(
this
);
}
else
{
onHostnameUpdated
();
}
}
@DebugLog
public
void
beforeLogoutCleanUp
()
{
presenter
.
beforeLogoutCleanUp
();
}
}
app/src/main/java/chat/rocket/android/activity/MainContract.java
View file @
5bbd3f7f
...
...
@@ -26,6 +26,8 @@ public interface MainContract {
void
showConnectionOk
();
void
showSignedInServers
(
List
<
Pair
<
String
,
Pair
<
String
,
String
>>>
serverList
);
void
refreshRoom
();
}
interface
Presenter
extends
BaseContract
.
Presenter
<
View
>
{
...
...
app/src/main/java/chat/rocket/android/activity/MainPresenter.java
View file @
5bbd3f7f
...
...
@@ -18,6 +18,7 @@ import chat.rocket.android.log.RCLog;
import
chat.rocket.android.service.ConnectivityManagerApi
;
import
chat.rocket.android.service.ServerConnectivity
;
import
chat.rocket.android.shared.BasePresenter
;
import
chat.rocket.android_ddp.DDPClient
;
import
chat.rocket.core.PublicSettingsConstants
;
import
chat.rocket.core.interactors.CanCreateRoomInteractor
;
import
chat.rocket.core.interactors.RoomInteractor
;
...
...
@@ -27,225 +28,230 @@ import chat.rocket.core.models.Session;
import
chat.rocket.core.models.User
;
import
chat.rocket.core.repositories.PublicSettingRepository
;
import
chat.rocket.core.utils.Pair
;
import
hu.akarnokd.rxjava.interop.RxJavaInterop
;
import
io.reactivex.Flowable
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.reactivex.disposables.Disposable
;
public
class
MainPresenter
extends
BasePresenter
<
MainContract
.
View
>
implements
MainContract
.
Presenter
{
private
final
CanCreateRoomInteractor
canCreateRoomInteractor
;
private
final
RoomInteractor
roomInteractor
;
private
final
SessionInteractor
sessionInteractor
;
private
final
MethodCallHelper
methodCallHelper
;
private
final
ConnectivityManagerApi
connectivityManagerApi
;
private
final
RocketChatCache
rocketChatCache
;
private
final
PublicSettingRepository
publicSettingRepository
;
public
MainPresenter
(
RoomInteractor
roomInteractor
,
CanCreateRoomInteractor
canCreateRoomInteractor
,
SessionInteractor
sessionInteractor
,
MethodCallHelper
methodCallHelper
,
ConnectivityManagerApi
connectivityManagerApi
,
RocketChatCache
rocketChatCache
,
PublicSettingRepository
publicSettingRepository
)
{
this
.
roomInteractor
=
roomInteractor
;
this
.
canCreateRoomInteractor
=
canCreateRoomInteractor
;
this
.
sessionInteractor
=
sessionInteractor
;
this
.
methodCallHelper
=
methodCallHelper
;
this
.
connectivityManagerApi
=
connectivityManagerApi
;
this
.
rocketChatCache
=
rocketChatCache
;
this
.
publicSettingRepository
=
publicSettingRepository
;
}
@Override
public
void
bindViewOnly
(
@NonNull
MainContract
.
View
view
)
{
super
.
bindView
(
view
);
subscribeToUnreadCount
();
subscribeToSession
();
setUserOnline
();
}
@Override
public
void
loadSignedInServers
(
@NonNull
String
hostname
)
{
final
Disposable
disposable
=
publicSettingRepository
.
getById
(
PublicSettingsConstants
.
Assets
.
LOGO
)
.
zipWith
(
publicSettingRepository
.
getById
(
PublicSettingsConstants
.
General
.
SITE_NAME
),
Pair:
:
new
)
.
map
(
this
::
getLogoAndSiteNamePair
)
.
map
(
settings
->
getServerList
(
hostname
,
settings
))
.
subscribeOn
(
AndroidSchedulers
.
from
(
BackgroundLooper
.
get
()))
.
observeOn
(
AndroidSchedulers
.
mainThread
())
.
subscribe
(
view:
:
showSignedInServers
,
RCLog:
:
e
);
addSubscription
(
disposable
);
}
@Override
public
void
bindView
(
@NonNull
MainContract
.
View
view
)
{
super
.
bindView
(
view
);
if
(
shouldLaunchAddServerActivity
())
{
view
.
showAddServerScreen
();
return
;
}
openRoom
();
subscribeToNetworkChanges
();
subscribeToUnreadCount
();
subscribeToSession
();
setUserOnline
();
}
@Override
public
void
release
()
{
setUserAway
();
super
.
release
();
}
@Override
public
void
onOpenRoom
(
String
hostname
,
String
roomId
)
{
final
Disposable
subscription
=
canCreateRoomInteractor
.
canCreate
(
roomId
)
.
subscribeOn
(
AndroidSchedulers
.
from
(
BackgroundLooper
.
get
()))
.
observeOn
(
AndroidSchedulers
.
mainThread
())
.
subscribe
(
allowed
->
{
if
(
allowed
)
{
view
.
showRoom
(
hostname
,
roomId
);
}
else
{
view
.
showHome
();
}
},
Logger:
:
report
);
addSubscription
(
subscription
);
}
@Override
public
void
onRetryLogin
()
{
final
Disposable
subscription
=
sessionInteractor
.
retryLogin
()
.
subscribe
();
addSubscription
(
subscription
);
}
@Override
public
void
beforeLogoutCleanUp
()
{
clearSubscriptions
();
}
private
Pair
<
String
,
String
>
getLogoAndSiteNamePair
(
Pair
<
Optional
<
PublicSetting
>,
Optional
<
PublicSetting
>>
settingsPair
)
{
String
logoUrl
=
""
;
String
siteName
=
""
;
if
(
settingsPair
.
first
.
isPresent
())
{
logoUrl
=
settingsPair
.
first
.
get
().
getValue
();
}
if
(
settingsPair
.
second
.
isPresent
())
{
siteName
=
settingsPair
.
second
.
get
().
getValue
();
}
return
new
Pair
<>(
logoUrl
,
siteName
);
}
private
List
<
Pair
<
String
,
Pair
<
String
,
String
>>>
getServerList
(
String
hostname
,
Pair
<
String
,
String
>
serverInfoPair
)
throws
JSONException
{
JSONObject
jsonObject
=
new
JSONObject
(
serverInfoPair
.
first
);
String
logoUrl
=
(
jsonObject
.
has
(
"url"
))
?
jsonObject
.
optString
(
"url"
)
:
jsonObject
.
optString
(
"defaultUrl"
);
String
siteName
=
serverInfoPair
.
second
;
rocketChatCache
.
addHostname
(
hostname
.
toLowerCase
(),
logoUrl
,
siteName
);
return
rocketChatCache
.
getServerList
();
}
private
void
openRoom
()
{
String
hostname
=
rocketChatCache
.
getSelectedServerHostname
();
String
roomId
=
rocketChatCache
.
getSelectedRoomId
();
if
(
roomId
==
null
||
roomId
.
length
()
==
0
)
{
view
.
showHome
();
return
;
}
onOpenRoom
(
hostname
,
roomId
);
}
private
void
subscribeToUnreadCount
()
{
final
Disposable
subscription
=
Flowable
.
combineLatest
(
roomInteractor
.
getTotalUnreadRoomsCount
(),
roomInteractor
.
getTotalUnreadMentionsCount
(),
(
Pair:
:
new
)
)
.
subscribeOn
(
AndroidSchedulers
.
from
(
BackgroundLooper
.
get
()))
.
observeOn
(
AndroidSchedulers
.
mainThread
())
.
subscribe
(
pair
->
view
.
showUnreadCount
(
pair
.
first
,
pair
.
second
),
Logger:
:
report
);
addSubscription
(
subscription
);
}
private
void
subscribeToSession
()
{
final
Disposable
subscription
=
sessionInteractor
.
getDefault
()
.
subscribeOn
(
AndroidSchedulers
.
from
(
BackgroundLooper
.
get
()))
.
observeOn
(
AndroidSchedulers
.
mainThread
())
.
subscribe
(
sessionOptional
->
{
Session
session
=
sessionOptional
.
orNull
();
if
(
session
==
null
||
session
.
getToken
()
==
null
)
{
view
.
showLoginScreen
();
return
;
}
String
error
=
session
.
getError
();
if
(
error
!=
null
&&
error
.
length
()
!=
0
)
{
view
.
showConnectionError
();
return
;
}
if
(!
session
.
isTokenVerified
())
{
view
.
showConnecting
();
return
;
}
view
.
showConnectionOk
();
},
Logger:
:
report
);
addSubscription
(
subscription
);
}
private
void
subscribeToNetworkChanges
()
{
Disposable
disposable
=
RxJavaInterop
.
toV2Flowable
(
connectivityManagerApi
.
getServerConnectivityAsObservable
())
.
observeOn
(
AndroidSchedulers
.
mainThread
())
.
subscribe
(
connectivity
->
{
if
(
connectivity
.
state
==
ServerConnectivity
.
STATE_CONNECTED
)
{
view
.
showConnectionOk
();
return
;
}
view
.
showConnecting
();
},
Logger:
:
report
);
addSubscription
(
disposable
);
}
private
void
setUserOnline
()
{
methodCallHelper
.
setUserPresence
(
User
.
STATUS_ONLINE
)
.
continueWith
(
new
LogIfError
());
}
private
void
setUserAway
()
{
methodCallHelper
.
setUserPresence
(
User
.
STATUS_AWAY
)
.
continueWith
(
new
LogIfError
());
}
private
boolean
shouldLaunchAddServerActivity
()
{
return
connectivityManagerApi
.
getServerList
().
isEmpty
();
}
implements
MainContract
.
Presenter
{
private
final
CanCreateRoomInteractor
canCreateRoomInteractor
;
private
final
RoomInteractor
roomInteractor
;
private
final
SessionInteractor
sessionInteractor
;
private
final
MethodCallHelper
methodCallHelper
;
private
final
ConnectivityManagerApi
connectivityManagerApi
;
private
final
RocketChatCache
rocketChatCache
;
private
final
PublicSettingRepository
publicSettingRepository
;
public
MainPresenter
(
RoomInteractor
roomInteractor
,
CanCreateRoomInteractor
canCreateRoomInteractor
,
SessionInteractor
sessionInteractor
,
MethodCallHelper
methodCallHelper
,
ConnectivityManagerApi
connectivityManagerApi
,
RocketChatCache
rocketChatCache
,
PublicSettingRepository
publicSettingRepository
)
{
this
.
roomInteractor
=
roomInteractor
;
this
.
canCreateRoomInteractor
=
canCreateRoomInteractor
;
this
.
sessionInteractor
=
sessionInteractor
;
this
.
methodCallHelper
=
methodCallHelper
;
this
.
connectivityManagerApi
=
connectivityManagerApi
;
this
.
rocketChatCache
=
rocketChatCache
;
this
.
publicSettingRepository
=
publicSettingRepository
;
}
@Override
public
void
bindViewOnly
(
@NonNull
MainContract
.
View
view
)
{
super
.
bindView
(
view
);
subscribeToUnreadCount
();
subscribeToSession
();
setUserOnline
();
}
@Override
public
void
loadSignedInServers
(
@NonNull
String
hostname
)
{
final
Disposable
disposable
=
publicSettingRepository
.
getById
(
PublicSettingsConstants
.
Assets
.
LOGO
)
.
zipWith
(
publicSettingRepository
.
getById
(
PublicSettingsConstants
.
General
.
SITE_NAME
),
Pair:
:
new
)
.
map
(
this
::
getLogoAndSiteNamePair
)
.
map
(
settings
->
getServerList
(
hostname
,
settings
))
.
subscribeOn
(
AndroidSchedulers
.
from
(
BackgroundLooper
.
get
()))
.
observeOn
(
AndroidSchedulers
.
mainThread
())
.
subscribe
(
view:
:
showSignedInServers
,
RCLog:
:
e
);
addSubscription
(
disposable
);
}
@Override
public
void
bindView
(
@NonNull
MainContract
.
View
view
)
{
super
.
bindView
(
view
);
if
(
shouldLaunchAddServerActivity
())
{
view
.
showAddServerScreen
();
return
;
}
openRoom
();
subscribeToNetworkChanges
();
subscribeToUnreadCount
();
subscribeToSession
();
setUserOnline
();
}
@Override
public
void
release
()
{
setUserAway
();
super
.
release
();
}
@Override
public
void
onOpenRoom
(
String
hostname
,
String
roomId
)
{
final
Disposable
subscription
=
canCreateRoomInteractor
.
canCreate
(
roomId
)
.
subscribeOn
(
AndroidSchedulers
.
from
(
BackgroundLooper
.
get
()))
.
observeOn
(
AndroidSchedulers
.
mainThread
())
.
subscribe
(
allowed
->
{
if
(
allowed
)
{
view
.
showRoom
(
hostname
,
roomId
);
}
else
{
view
.
showHome
();
}
},
Logger:
:
report
);
addSubscription
(
subscription
);
}
@Override
public
void
onRetryLogin
()
{
final
Disposable
subscription
=
sessionInteractor
.
retryLogin
()
.
subscribe
();
addSubscription
(
subscription
);
}
@Override
public
void
beforeLogoutCleanUp
()
{
clearSubscriptions
();
}
private
Pair
<
String
,
String
>
getLogoAndSiteNamePair
(
Pair
<
Optional
<
PublicSetting
>,
Optional
<
PublicSetting
>>
settingsPair
)
{
String
logoUrl
=
""
;
String
siteName
=
""
;
if
(
settingsPair
.
first
.
isPresent
())
{
logoUrl
=
settingsPair
.
first
.
get
().
getValue
();
}
if
(
settingsPair
.
second
.
isPresent
())
{
siteName
=
settingsPair
.
second
.
get
().
getValue
();
}
return
new
Pair
<>(
logoUrl
,
siteName
);
}
private
List
<
Pair
<
String
,
Pair
<
String
,
String
>>>
getServerList
(
String
hostname
,
Pair
<
String
,
String
>
serverInfoPair
)
throws
JSONException
{
JSONObject
jsonObject
=
new
JSONObject
(
serverInfoPair
.
first
);
String
logoUrl
=
(
jsonObject
.
has
(
"url"
))
?
jsonObject
.
optString
(
"url"
)
:
jsonObject
.
optString
(
"defaultUrl"
);
String
siteName
=
serverInfoPair
.
second
;
rocketChatCache
.
addHostname
(
hostname
.
toLowerCase
(),
logoUrl
,
siteName
);
return
rocketChatCache
.
getServerList
();
}
private
void
openRoom
()
{
String
hostname
=
rocketChatCache
.
getSelectedServerHostname
();
String
roomId
=
rocketChatCache
.
getSelectedRoomId
();
if
(
roomId
==
null
||
roomId
.
length
()
==
0
)
{
view
.
showHome
();
return
;
}
onOpenRoom
(
hostname
,
roomId
);
}
private
void
subscribeToUnreadCount
()
{
final
Disposable
subscription
=
Flowable
.
combineLatest
(
roomInteractor
.
getTotalUnreadRoomsCount
(),
roomInteractor
.
getTotalUnreadMentionsCount
(),
(
Pair:
:
new
)
)
.
subscribeOn
(
AndroidSchedulers
.
from
(
BackgroundLooper
.
get
()))
.
observeOn
(
AndroidSchedulers
.
mainThread
())
.
subscribe
(
pair
->
view
.
showUnreadCount
(
pair
.
first
,
pair
.
second
),
Logger:
:
report
);
addSubscription
(
subscription
);
}
private
void
subscribeToSession
()
{
final
Disposable
subscription
=
sessionInteractor
.
getDefault
()
.
subscribeOn
(
AndroidSchedulers
.
from
(
BackgroundLooper
.
get
()))
.
observeOn
(
AndroidSchedulers
.
mainThread
())
.
subscribe
(
sessionOptional
->
{
Session
session
=
sessionOptional
.
orNull
();
if
(
session
==
null
||
session
.
getToken
()
==
null
)
{
view
.
showLoginScreen
();
return
;
}
String
error
=
session
.
getError
();
if
(
error
!=
null
&&
error
.
length
()
!=
0
)
{
view
.
showConnectionError
();
return
;
}
if
(!
session
.
isTokenVerified
())
{
view
.
showConnecting
();
return
;
}
view
.
showConnectionOk
();
},
Logger:
:
report
);
addSubscription
(
subscription
);
}
private
void
subscribeToNetworkChanges
()
{
Disposable
disposable
=
connectivityManagerApi
.
getServerConnectivityAsObservable
()
.
distinctUntilChanged
()
.
observeOn
(
AndroidSchedulers
.
mainThread
())
.
subscribe
(
connectivity
->
{
if
(
connectivity
.
state
==
ServerConnectivity
.
STATE_CONNECTED
)
{
view
.
showConnectionOk
();
view
.
refreshRoom
();
}
else
if
(
connectivity
.
state
==
ServerConnectivity
.
STATE_DISCONNECTED
)
{
if
(
connectivity
.
code
==
DDPClient
.
REASON_NETWORK_ERROR
)
{
view
.
showConnectionError
();
}
}
else
{
view
.
showConnecting
();
}
},
Logger:
:
report
);
addSubscription
(
disposable
);
}
private
void
setUserOnline
()
{
methodCallHelper
.
setUserPresence
(
User
.
STATUS_ONLINE
)
.
continueWith
(
new
LogIfError
());
}
private
void
setUserAway
()
{
methodCallHelper
.
setUserPresence
(
User
.
STATUS_AWAY
)
.
continueWith
(
new
LogIfError
());
}
private
boolean
shouldLaunchAddServerActivity
()
{
return
connectivityManagerApi
.
getServerList
().
isEmpty
();
}
}
app/src/main/java/chat/rocket/android/activity/room/RoomActivity.kt
View file @
5bbd3f7f
...
...
@@ -5,6 +5,7 @@ import android.support.v4.app.Fragment
import
android.support.v7.app.AppCompatActivity
import
chat.rocket.android.R
import
chat.rocket.android.fragment.chatroom.list.RoomListFragment
import
chat.rocket.core.models.Room
import
kotlinx.android.synthetic.main.activity_room.*
class
RoomActivity
:
AppCompatActivity
()
{
...
...
@@ -20,7 +21,7 @@ class RoomActivity : AppCompatActivity() {
val
extras
=
intent
.
extras
val
roomListFragment
=
RoomListFragment
.
newInstance
(
extras
.
getInt
(
"actionId"
),
extras
.
getString
(
"roomId"
),
extras
.
getString
(
"roomType"
),
extras
.
getString
(
"roomType"
,
Room
.
TYPE_GROUP
),
extras
.
getString
(
"hostname"
),
extras
.
getString
(
"token"
),
extras
.
getString
(
"userId"
))
...
...
app/src/main/java/chat/rocket/android/api/DDPClientWrapper.java
deleted
100644 → 0
View file @
1f3713b3
package
chat
.
rocket
.
android
.
api
;
import
android.support.annotation.Nullable
;
import
chat.rocket.android.helper.OkHttpHelper
;
import
org.json.JSONArray
;
import
org.json.JSONException
;
import
java.util.UUID
;
import
bolts.Task
;
import
chat.rocket.android.helper.TextUtils
;
import
chat.rocket.android.log.RCLog
;
import
chat.rocket.android_ddp.DDPClient
;
import
chat.rocket.android_ddp.DDPClientCallback
;
import
chat.rocket.android_ddp.DDPSubscription
;
import
io.reactivex.Flowable
;
import
io.reactivex.Maybe
;
/**
* DDP client wrapper.
*/
public
class
DDPClientWrapper
{
private
final
DDPClient
ddpClient
;
private
final
String
hostname
;
private
DDPClientWrapper
(
String
hostname
)
{
ddpClient
=
new
DDPClient
(
OkHttpHelper
.
INSTANCE
.
getClientForWebSocket
());
this
.
hostname
=
hostname
;
}
/**
* build new API client instance.
*/
public
static
DDPClientWrapper
create
(
String
hostname
)
{
return
new
DDPClientWrapper
(
hostname
);
}
/**
* Connect to WebSocket server with DDP client.
*/
public
Task
<
DDPClientCallback
.
Connect
>
connect
(
@Nullable
String
session
,
boolean
usesSecureConnection
)
{
final
String
protocol
=
usesSecureConnection
?
"wss://"
:
"ws://"
;
return
ddpClient
.
connect
(
protocol
+
hostname
+
"/websocket"
,
session
);
}
/**
* close connection.
*/
public
void
close
()
{
ddpClient
.
close
();
}
/**
* Subscribe with DDP client.
*/
public
Task
<
DDPSubscription
.
Ready
>
subscribe
(
final
String
name
,
JSONArray
param
)
{
final
String
subscriptionId
=
UUID
.
randomUUID
().
toString
();
RCLog
.
d
(
"sub:[%s]> %s(%s)"
,
subscriptionId
,
name
,
param
);
return
ddpClient
.
sub
(
subscriptionId
,
name
,
param
);
}
/**
* Unsubscribe with DDP client.
*/
public
Task
<
DDPSubscription
.
NoSub
>
unsubscribe
(
final
String
subscriptionId
)
{
RCLog
.
d
(
"unsub:[%s]>"
,
subscriptionId
);
return
ddpClient
.
unsub
(
subscriptionId
);
}
/**
* Returns Observable for handling DDP subscription.
*/
public
Flowable
<
DDPSubscription
.
Event
>
getSubscriptionCallback
()
{
return
ddpClient
.
getSubscriptionCallback
();
}
/**
* Execute raw RPC.
*/
public
Task
<
DDPClientCallback
.
RPC
>
rpc
(
String
methodCallId
,
String
methodName
,
String
params
,
long
timeoutMs
)
{
RCLog
.
d
(
"rpc:[%s]> %s(%s) timeout=%d"
,
methodCallId
,
methodName
,
params
,
timeoutMs
);
if
(
TextUtils
.
isEmpty
(
params
))
{
return
ddpClient
.
rpc
(
methodName
,
null
,
methodCallId
,
timeoutMs
).
continueWithTask
(
task
->
{
if
(
task
.
isFaulted
())
{
RCLog
.
d
(
"rpc:[%s]< error = %s"
,
methodCallId
,
task
.
getError
());
}
else
{
RCLog
.
d
(
"rpc:[%s]< result = %s"
,
methodCallId
,
task
.
getResult
().
result
);
}
return
task
;
});
}
try
{
return
ddpClient
.
rpc
(
methodName
,
new
JSONArray
(
params
),
methodCallId
,
timeoutMs
)
.
continueWithTask
(
task
->
{
if
(
task
.
isFaulted
())
{
RCLog
.
d
(
"rpc:[%s]< error = %s"
,
methodCallId
,
task
.
getError
());
}
else
{
RCLog
.
d
(
"rpc:[%s]< result = %s"
,
methodCallId
,
task
.
getResult
().
result
);
}
return
task
;
});
}
catch
(
JSONException
exception
)
{
return
Task
.
forError
(
exception
);
}
}
/**
* check WebSocket connectivity with ping.
*/
public
Task
<
Void
>
ping
()
{
final
String
pingId
=
UUID
.
randomUUID
().
toString
();
RCLog
.
d
(
"ping[%s] >"
,
pingId
);
return
ddpClient
.
ping
(
pingId
)
.
continueWithTask
(
task
->
{
if
(
task
.
isFaulted
())
{
RCLog
.
d
(
task
.
getError
(),
"ping[%s] xxx failed xxx"
,
pingId
);
return
Task
.
forError
(
task
.
getError
());
}
else
{
RCLog
.
d
(
"pong[%s] <"
,
pingId
);
return
Task
.
forResult
(
null
);
}
});
}
/**
* check WebSocket connectivity with ping.
*/
public
Maybe
<
DDPClientCallback
.
Base
>
doPing
()
{
final
String
pingId
=
UUID
.
randomUUID
().
toString
();
RCLog
.
d
(
"ping[%s] >"
,
pingId
);
return
ddpClient
.
doPing
(
pingId
);
}
}
app/src/main/java/chat/rocket/android/api/FileUploadingHelper.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
api
;
import
android.content.Context
;
import
org.json.JSONArray
;
import
org.json.JSONObject
;
import
bolts.Task
;
import
chat.rocket.android.helper.TextUtils
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.android.service.DDPClientRef
;
/**
* MethodCall for uploading file.
...
...
@@ -17,8 +17,8 @@ public class FileUploadingHelper extends MethodCallHelper {
super
(
context
,
hostname
);
}
public
FileUploadingHelper
(
RealmHelper
realmHelper
,
DDPClientRef
ddpClientRef
)
{
super
(
realmHelper
,
ddpClientRef
);
public
FileUploadingHelper
(
RealmHelper
realmHelper
)
{
super
(
realmHelper
);
}
public
Task
<
JSONObject
>
uploadS3Request
(
String
filename
,
long
filesize
,
String
mimeType
,
...
...
app/src/main/java/chat/rocket/android/api/MethodCallHelper.java
View file @
5bbd3f7f
...
...
@@ -11,11 +11,13 @@ import java.util.UUID;
import
bolts.Continuation
;
import
bolts.Task
;
import
chat.rocket.android.RocketChatCache
;
import
chat.rocket.android.helper.CheckSum
;
import
chat.rocket.android.helper.TextUtils
;
import
chat.rocket.android.service.ConnectivityManager
;
import
chat.rocket.android
.service.DDPClientRef
;
import
chat.rocket.android
_ddp.DDPClient
;
import
chat.rocket.android_ddp.DDPClientCallback
;
import
chat.rocket.core.PublicSettingsConstants
;
import
chat.rocket.core.SyncState
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.persistence.realm.RealmStore
;
...
...
@@ -30,6 +32,7 @@ import chat.rocket.persistence.realm.models.ddp.RealmSpotlightUser;
import
chat.rocket.persistence.realm.models.internal.MethodCall
;
import
chat.rocket.persistence.realm.models.internal.RealmSession
;
import
hugo.weaving.DebugLog
;
import
okhttp3.HttpUrl
;
/**
* Utility class for creating/handling MethodCall or RPC.
...
...
@@ -45,7 +48,6 @@ public class MethodCallHelper {
task
->
Task
.
forResult
(
new
JSONArray
(
task
.
getResult
()));
protected
final
Context
context
;
protected
final
RealmHelper
realmHelper
;
protected
final
DDPClientRef
ddpClientRef
;
/**
* initialize with Context and hostname.
...
...
@@ -53,23 +55,32 @@ public class MethodCallHelper {
public
MethodCallHelper
(
Context
context
,
String
hostname
)
{
this
.
context
=
context
.
getApplicationContext
();
this
.
realmHelper
=
RealmStore
.
getOrCreate
(
hostname
);
ddpClientRef
=
null
;
}
/**
* initialize with RealmHelper and DDPClient.
*/
public
MethodCallHelper
(
RealmHelper
realmHelper
,
DDPClientRef
ddpClientRef
)
{
public
MethodCallHelper
(
RealmHelper
realmHelper
)
{
this
.
context
=
null
;
this
.
realmHelper
=
realmHelper
;
this
.
ddpClientRef
=
ddpClientRef
;
}
public
MethodCallHelper
(
Context
context
,
RealmHelper
realmHelper
)
{
this
.
context
=
context
.
getApplicationContext
();
this
.
realmHelper
=
realmHelper
;
}
@DebugLog
private
Task
<
String
>
executeMethodCall
(
String
methodName
,
String
param
,
long
timeout
)
{
if
(
ddpClientRef
!=
null
)
{
return
ddpClientRef
.
get
().
rpc
(
UUID
.
randomUUID
().
toString
(),
methodName
,
param
,
timeout
)
.
onSuccessTask
(
task
->
Task
.
forResult
(
task
.
getResult
().
result
));
if
(
DDPClient
.
get
()
!=
null
)
{
return
DDPClient
.
get
().
rpc
(
UUID
.
randomUUID
().
toString
(),
methodName
,
param
,
timeout
)
.
onSuccessTask
(
task
->
Task
.
forResult
(
task
.
getResult
().
result
))
.
continueWithTask
(
task_
->
{
if
(
task_
.
isFaulted
())
{
return
Task
.
forError
(
task_
.
getError
());
}
return
Task
.
forResult
(
task_
.
getResult
());
});
}
else
{
return
MethodCall
.
execute
(
realmHelper
,
methodName
,
param
,
timeout
)
.
onSuccessTask
(
task
->
{
...
...
@@ -84,8 +95,13 @@ public class MethodCallHelper {
return
task
.
continueWithTask
(
_task
->
{
if
(
_task
.
isFaulted
())
{
Exception
exception
=
_task
.
getError
();
if
(
exception
instanceof
MethodCall
.
Error
)
{
String
errMessageJson
=
exception
.
getMessage
();
if
(
exception
instanceof
MethodCall
.
Error
||
exception
instanceof
DDPClientCallback
.
RPC
.
Error
)
{
String
errMessageJson
;
if
(
exception
instanceof
DDPClientCallback
.
RPC
.
Error
)
{
errMessageJson
=
((
DDPClientCallback
.
RPC
.
Error
)
exception
).
error
.
toString
();
}
else
{
errMessageJson
=
exception
.
getMessage
();
}
if
(
TextUtils
.
isEmpty
(
errMessageJson
))
{
return
Task
.
forError
(
exception
);
}
...
...
@@ -96,11 +112,10 @@ public class MethodCallHelper {
return
Task
.
forError
(
new
TwoStepAuthException
(
errMessage
));
}
return
Task
.
forError
(
new
Exception
(
errMessage
));
}
else
if
(
exception
instanceof
DDPClientCallback
.
RPC
.
Error
)
{
String
errMessage
=
((
DDPClientCallback
.
RPC
.
Error
)
exception
).
error
.
getString
(
"message"
);
return
Task
.
forError
(
new
Exception
(
errMessage
));
}
else
if
(
exception
instanceof
DDPClientCallback
.
RPC
.
Timeout
)
{
return
Task
.
forError
(
new
MethodCall
.
Timeout
());
}
else
if
(
exception
instanceof
DDPClientCallback
.
Closed
)
{
return
Task
.
forError
(
new
Exception
(
"Oops, your connection seems off..."
));
}
else
{
return
Task
.
forError
(
exception
);
}
...
...
@@ -179,8 +194,8 @@ public class MethodCallHelper {
.
put
(
"algorithm"
,
"sha-256"
));
return
new
JSONArray
().
put
(
param
);
}).
onSuccessTask
(
CONVERT_TO_JSON_OBJECT
)
.
onSuccessTask
(
task
->
Task
.
forResult
(
task
.
getResult
().
getString
(
"token"
)))
.
onSuccessTask
(
this
::
saveToken
);
.
onSuccessTask
(
task
->
Task
.
forResult
(
task
.
getResult
().
getString
(
"token"
)))
.
onSuccessTask
(
this
::
saveToken
);
}
public
Task
<
Void
>
loginWithLdap
(
final
String
username
,
final
String
password
)
{
...
...
@@ -385,6 +400,17 @@ public class MethodCallHelper {
}
}
public
Task
<
Void
>
deleteMessage
(
String
messageID
)
{
try
{
JSONObject
messageJson
=
new
JSONObject
()
.
put
(
"_id"
,
messageID
);
return
deleteMessage
(
messageJson
);
}
catch
(
JSONException
exception
)
{
return
Task
.
forError
(
exception
);
}
}
/**
* Send message object.
*/
...
...
@@ -398,6 +424,11 @@ public class MethodCallHelper {
.
onSuccessTask
(
task
->
Task
.
forResult
(
null
));
}
private
Task
<
Void
>
deleteMessage
(
final
JSONObject
messageJson
)
{
return
call
(
"deleteMessage"
,
TIMEOUT_MS
,
()
->
new
JSONArray
().
put
(
messageJson
))
.
onSuccessTask
(
task
->
Task
.
forResult
(
null
));
}
/**
* mark all messages are read in the room.
*/
...
...
@@ -406,13 +437,31 @@ public class MethodCallHelper {
.
onSuccessTask
(
task
->
Task
.
forResult
(
null
));
}
public
Task
<
Void
>
getPublicSettings
()
{
public
Task
<
Void
>
getPublicSettings
(
String
currentHostname
)
{
return
call
(
"public-settings/get"
,
TIMEOUT_MS
)
.
onSuccessTask
(
CONVERT_TO_JSON_ARRAY
)
.
onSuccessTask
(
task
->
{
final
JSONArray
settings
=
task
.
getResult
();
String
siteUrl
=
null
;
String
siteName
=
null
;
for
(
int
i
=
0
;
i
<
settings
.
length
();
i
++)
{
RealmPublicSetting
.
customizeJson
(
settings
.
getJSONObject
(
i
));
JSONObject
jsonObject
=
settings
.
getJSONObject
(
i
);
RealmPublicSetting
.
customizeJson
(
jsonObject
);
if
(
isPublicSetting
(
jsonObject
,
PublicSettingsConstants
.
General
.
SITE_URL
))
{
siteUrl
=
jsonObject
.
getString
(
RealmPublicSetting
.
VALUE
);
}
else
if
(
isPublicSetting
(
jsonObject
,
PublicSettingsConstants
.
General
.
SITE_NAME
))
{
siteName
=
jsonObject
.
getString
(
RealmPublicSetting
.
VALUE
);
}
}
if
(
siteName
!=
null
&&
siteUrl
!=
null
)
{
HttpUrl
httpSiteUrl
=
HttpUrl
.
parse
(
siteUrl
);
if
(
httpSiteUrl
!=
null
)
{
String
host
=
httpSiteUrl
.
host
();
RocketChatCache
rocketChatCache
=
new
RocketChatCache
(
context
);
rocketChatCache
.
addHostnameSiteUrl
(
host
,
currentHostname
);
rocketChatCache
.
addHostSiteName
(
currentHostname
,
siteName
);
}
}
return
realmHelper
.
executeTransaction
(
realm
->
{
...
...
@@ -423,6 +472,10 @@ public class MethodCallHelper {
});
}
private
boolean
isPublicSetting
(
JSONObject
jsonObject
,
String
id
)
{
return
jsonObject
.
optString
(
RealmPublicSetting
.
ID
).
equalsIgnoreCase
(
id
);
}
public
Task
<
Void
>
getPermissions
()
{
return
call
(
"permissions/get"
,
TIMEOUT_MS
)
.
onSuccessTask
(
CONVERT_TO_JSON_ARRAY
)
...
...
app/src/main/java/chat/rocket/android/api/RaixPushHelper.java
View file @
5bbd3f7f
...
...
@@ -3,21 +3,20 @@ package chat.rocket.android.api;
import
android.content.Context
;
import
android.support.annotation.NonNull
;
import
android.support.annotation.Nullable
;
import
org.json.JSONArray
;
import
org.json.JSONObject
;
import
bolts.Task
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.android.service.DDPClientRef
;
public
class
RaixPushHelper
extends
MethodCallHelper
{
public
RaixPushHelper
(
Context
context
,
String
hostname
)
{
super
(
context
,
hostname
);
}
public
RaixPushHelper
(
RealmHelper
realmHelper
,
DDPClientRef
ddpClientRef
)
{
super
(
realmHelper
,
ddpClientRef
);
public
RaixPushHelper
(
RealmHelper
realmHelper
)
{
super
(
realmHelper
);
}
public
Task
<
Void
>
pushUpdate
(
@NonNull
String
pushId
,
@NonNull
String
gcmToken
,
...
...
app/src/main/java/chat/rocket/android/api/rest/CookieInterceptor.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
api
.
rest
;
import
java.io.IOException
;
import
chat.rocket.android.helper.TextUtils
;
import
okhttp3.Interceptor
;
import
okhttp3.Request
;
...
...
app/src/main/java/chat/rocket/android/api/rest/DefaultCookieProvider.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
api
.
rest
;
import
chat.rocket.android.RocketChatCache
;
import
chat.rocket.persistence.realm.models.ddp.RealmUser
;
import
chat.rocket.persistence.realm.models.internal.RealmSession
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.persistence.realm.RealmStore
;
import
chat.rocket.persistence.realm.models.ddp.RealmUser
;
import
chat.rocket.persistence.realm.models.internal.RealmSession
;
public
class
DefaultCookieProvider
implements
CookieProvider
{
...
...
app/src/main/java/chat/rocket/android/api/rest/DefaultServerPolicyApi.java
View file @
5bbd3f7f
...
...
@@ -2,12 +2,13 @@ package chat.rocket.android.api.rest;
import
android.support.annotation.NonNull
;
import
io.reactivex.BackpressureStrategy
;
import
io.reactivex.Flowable
;
import
io.reactivex.FlowableEmitter
;
import
org.json.JSONObject
;
import
java.io.IOException
;
import
io.reactivex.BackpressureStrategy
;
import
io.reactivex.Flowable
;
import
io.reactivex.FlowableEmitter
;
import
okhttp3.Call
;
import
okhttp3.OkHttpClient
;
import
okhttp3.Request
;
...
...
app/src/main/java/chat/rocket/android/api/rest/ServerPolicyApi.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
api
.
rest
;
import
io.reactivex.Flowable
;
import
org.json.JSONObject
;
import
io.reactivex.Flowable
;
public
interface
ServerPolicyApi
{
String
SECURE_PROTOCOL
=
"https://"
;
...
...
app/src/main/java/chat/rocket/android/fragment/AbstractFragment.java
View file @
5bbd3f7f
...
...
@@ -6,6 +6,7 @@ import android.support.annotation.Nullable;
import
android.view.LayoutInflater
;
import
android.view.View
;
import
android.view.ViewGroup
;
import
com.trello.rxlifecycle2.components.support.RxFragment
;
/**
...
...
app/src/main/java/chat/rocket/android/fragment/add_server/InputHostnameFragment.java
View file @
5bbd3f7f
...
...
@@ -7,6 +7,7 @@ import android.support.constraint.ConstraintLayout;
import
android.support.design.widget.Snackbar
;
import
android.view.View
;
import
android.widget.TextView
;
import
chat.rocket.android.BuildConfig
;
import
chat.rocket.android.LaunchUtil
;
import
chat.rocket.android.R
;
...
...
app/src/main/java/chat/rocket/android/fragment/add_server/InputHostnamePresenter.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
fragment
.
add_server
;
import
chat.rocket.android.BackgroundLooper
;
import
chat.rocket.android.helper.Logger
;
import
chat.rocket.android.helper.OkHttpHelper
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.reactivex.disposables.Disposable
;
import
chat.rocket.android.RocketChatCache
;
import
chat.rocket.android.api.rest.DefaultServerPolicyApi
;
import
chat.rocket.android.api.rest.ServerPolicyApi
;
import
chat.rocket.android.helper.Logger
;
import
chat.rocket.android.helper.OkHttpHelper
;
import
chat.rocket.android.helper.ServerPolicyApiValidationHelper
;
import
chat.rocket.android.helper.ServerPolicyHelper
;
import
chat.rocket.android.service.ConnectivityManagerApi
;
import
chat.rocket.android.shared.BasePresenter
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.reactivex.disposables.Disposable
;
public
class
InputHostnamePresenter
extends
BasePresenter
<
InputHostnameContract
.
View
>
implements
InputHostnameContract
.
Presenter
{
private
final
RocketChatCache
rocketChatCache
;
...
...
app/src/main/java/chat/rocket/android/fragment/chatroom/RoomContract.java
View file @
5bbd3f7f
...
...
@@ -35,6 +35,8 @@ public interface RoomContract {
void
showMessageSendFailure
(
Message
message
);
void
showMessageDeleteFailure
(
Message
message
);
void
autoloadImages
();
void
manualLoadImages
();
...
...
@@ -71,5 +73,7 @@ public interface RoomContract {
void
refreshRoom
();
void
replyMessage
(
@NonNull
Message
message
,
boolean
justQuote
);
void
acceptMessageDeleteFailure
(
Message
message
);
}
}
app/src/main/java/chat/rocket/android/fragment/chatroom/RoomFragment.java
View file @
5bbd3f7f
...
...
@@ -647,6 +647,15 @@ public class RoomFragment extends AbstractChatRoomFragment implements
.
show
();
}
@Override
public
void
showMessageDeleteFailure
(
Message
message
)
{
new
AlertDialog
.
Builder
(
getContext
())
.
setTitle
(
getContext
().
getString
(
R
.
string
.
failed_to_delete
))
.
setMessage
(
getContext
().
getString
(
R
.
string
.
failed_to_delete_message
))
.
setPositiveButton
(
R
.
string
.
ok
,
(
dialog
,
which
)
->
presenter
.
acceptMessageDeleteFailure
(
message
))
.
show
();
}
@Override
public
void
autoloadImages
()
{
messageListAdapter
.
setAutoloadImages
(
true
);
...
...
@@ -679,6 +688,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements
.
setEditAction
(
this
::
onEditMessage
)
.
setCopyAction
(
msg
->
onCopy
(
message
.
getMessage
()))
.
setQuoteAction
(
msg
->
presenter
.
replyMessage
(
message
,
true
))
.
setDeleteAction
(
this
::
onDeleteMessage
)
.
showWith
(
context
);
}
}
...
...
@@ -688,6 +698,10 @@ public class RoomFragment extends AbstractChatRoomFragment implements
messageFormManager
.
setEditMessage
(
message
.
getMessage
());
}
public
void
onDeleteMessage
(
Message
message
)
{
presenter
.
deleteMessage
(
message
);
}
private
void
showRoomListFragment
(
int
actionId
)
{
//TODO: oddly sometimes getActivity() yields null. Investigate the situations this might happen
//and fix it, removing this null-check
...
...
@@ -701,4 +715,8 @@ public class RoomFragment extends AbstractChatRoomFragment implements
startActivity
(
intent
);
}
}
public
void
loadMessages
()
{
presenter
.
loadMessages
();
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/fragment/chatroom/RoomPresenter.java
View file @
5bbd3f7f
...
...
@@ -112,7 +112,11 @@ public class RoomPresenter extends BasePresenter<RoomContract.View>
return
;
}
if
(
message
.
getType
()
==
null
&&
message
.
getSyncState
()
==
SyncState
.
SYNCED
)
{
if
(
message
.
getSyncState
()
==
SyncState
.
DELETE_FAILED
)
{
view
.
showMessageDeleteFailure
(
message
);
}
else
if
(
message
.
getSyncState
()
==
SyncState
.
FAILED
)
{
view
.
showMessageSendFailure
(
message
);
}
else
if
(
message
.
getType
()
==
null
&&
message
.
getSyncState
()
==
SyncState
.
SYNCED
)
{
// If message is not a system message show applicable actions.
view
.
showMessageActions
(
message
);
}
...
...
@@ -147,6 +151,15 @@ public class RoomPresenter extends BasePresenter<RoomContract.View>
);
}
public
void
acceptMessageDeleteFailure
(
Message
message
)
{
final
Disposable
subscription
=
messageInteractor
.
acceptDeleteFailure
(
message
)
.
subscribeOn
(
AndroidSchedulers
.
from
(
BackgroundLooper
.
get
()))
.
observeOn
(
AndroidSchedulers
.
mainThread
())
.
subscribe
();
addSubscription
(
subscription
);
}
private
String
buildReplyOrQuoteMarkdown
(
String
baseUrl
,
Message
message
,
boolean
justQuote
)
{
if
(
currentRoom
==
null
||
message
.
getUser
()
==
null
)
{
return
""
;
...
...
app/src/main/java/chat/rocket/android/fragment/chatroom/dialog/MessageOptionsDialogFragment.java
View file @
5bbd3f7f
...
...
@@ -10,11 +10,6 @@ import android.support.v4.util.Pair;
import
android.view.View
;
import
android.widget.TextView
;
import
io.reactivex.Single
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.reactivex.disposables.CompositeDisposable
;
import
io.reactivex.disposables.Disposable
;
import
chat.rocket.android.BackgroundLooper
;
import
chat.rocket.android.R
;
import
chat.rocket.android.RocketChatCache
;
...
...
@@ -34,6 +29,10 @@ import chat.rocket.persistence.realm.repositories.RealmPublicSettingRepository;
import
chat.rocket.persistence.realm.repositories.RealmRoomRepository
;
import
chat.rocket.persistence.realm.repositories.RealmRoomRoleRepository
;
import
chat.rocket.persistence.realm.repositories.RealmUserRepository
;
import
io.reactivex.Single
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.reactivex.disposables.CompositeDisposable
;
import
io.reactivex.disposables.Disposable
;
public
class
MessageOptionsDialogFragment
extends
BottomSheetDialogFragment
{
...
...
app/src/main/java/chat/rocket/android/fragment/chatroom/list/RoomListFragment.kt
View file @
5bbd3f7f
...
...
@@ -47,20 +47,23 @@ class RoomListFragment : Fragment(), RoomListContract.View {
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
super
.
onCreate
(
savedInstanceState
)
activity
.
title
=
""
actionId
=
arguments
.
getInt
(
"actionId"
)
roomId
=
arguments
.
getString
(
"roomId"
)
roomType
=
arguments
.
getString
(
"roomType"
)
hostname
=
arguments
.
getString
(
"hostname"
)
token
=
arguments
.
getString
(
"token"
)
userId
=
arguments
.
getString
(
"userId"
)
activity
?.
title
=
""
val
args
=
arguments
args
?.
let
{
actionId
=
args
.
getInt
(
"actionId"
)
roomId
=
args
.
getString
(
"roomId"
)
roomType
=
args
.
getString
(
"roomType"
)
hostname
=
args
.
getString
(
"hostname"
)
token
=
args
.
getString
(
"token"
)
userId
=
args
.
getString
(
"userId"
)
}
}
override
fun
onCreateView
(
inflater
:
LayoutInflater
?,
container
:
ViewGroup
?,
savedInstanceState
:
Bundle
?):
View
?
=
inflater
?
.
inflate
(
R
.
layout
.
fragment_room_list
,
container
,
false
)
override
fun
onCreateView
(
inflater
:
LayoutInflater
,
container
:
ViewGroup
?,
savedInstanceState
:
Bundle
?):
View
?
=
inflater
.
inflate
(
R
.
layout
.
fragment_room_list
,
container
,
false
)
override
fun
onViewCreated
(
view
:
View
?
,
savedInstanceState
:
Bundle
?)
{
override
fun
onViewCreated
(
view
:
View
,
savedInstanceState
:
Bundle
?)
{
super
.
onViewCreated
(
view
,
savedInstanceState
)
presenter
=
RoomListPresenter
(
context
,
this
)
presenter
=
RoomListPresenter
(
context
!!
,
this
)
}
override
fun
onResume
()
{
...
...
@@ -114,9 +117,9 @@ class RoomListFragment : Fragment(), RoomListContract.View {
}
override
fun
showPinnedMessages
(
dataSet
:
ArrayList
<
Message
>,
total
:
String
)
{
activity
.
title
=
getString
(
R
.
string
.
fragment_room_list_pinned_message_title
,
total
)
activity
?
.
title
=
getString
(
R
.
string
.
fragment_room_list_pinned_message_title
,
total
)
if
(
recyclerView
.
adapter
==
null
)
{
recyclerView
.
adapter
=
RoomMessagesAdapter
(
dataSet
,
hostname
,
context
)
recyclerView
.
adapter
=
RoomMessagesAdapter
(
dataSet
,
hostname
,
context
!!
)
val
linearLayoutManager
=
LinearLayoutManager
(
context
,
LinearLayoutManager
.
VERTICAL
,
false
)
recyclerView
.
layoutManager
=
linearLayoutManager
if
(
dataSet
.
size
>=
50
)
{
...
...
@@ -132,9 +135,9 @@ class RoomListFragment : Fragment(), RoomListContract.View {
}
override
fun
showFavoriteMessages
(
dataSet
:
ArrayList
<
Message
>,
total
:
String
)
{
activity
.
title
=
getString
(
R
.
string
.
fragment_room_list_favorite_message_title
,
total
)
activity
?
.
title
=
getString
(
R
.
string
.
fragment_room_list_favorite_message_title
,
total
)
if
(
recyclerView
.
adapter
==
null
)
{
recyclerView
.
adapter
=
RoomMessagesAdapter
(
dataSet
,
hostname
,
context
)
recyclerView
.
adapter
=
RoomMessagesAdapter
(
dataSet
,
hostname
,
context
!!
)
val
linearLayoutManager
=
LinearLayoutManager
(
context
,
LinearLayoutManager
.
VERTICAL
,
false
)
recyclerView
.
layoutManager
=
linearLayoutManager
if
(
dataSet
.
size
>=
50
)
{
...
...
@@ -150,7 +153,7 @@ class RoomListFragment : Fragment(), RoomListContract.View {
}
override
fun
showFileList
(
dataSet
:
ArrayList
<
Attachment
>,
total
:
String
)
{
activity
.
title
=
getString
(
R
.
string
.
fragment_room_list_file_list_title
,
total
)
activity
?
.
title
=
getString
(
R
.
string
.
fragment_room_list_file_list_title
,
total
)
if
(
recyclerView
.
adapter
==
null
)
{
recyclerView
.
adapter
=
RoomFileListAdapter
(
dataSet
)
val
linearLayoutManager
=
LinearLayoutManager
(
context
,
LinearLayoutManager
.
VERTICAL
,
false
)
...
...
@@ -168,9 +171,9 @@ class RoomListFragment : Fragment(), RoomListContract.View {
}
override
fun
showMemberList
(
dataSet
:
ArrayList
<
User
>,
total
:
String
)
{
activity
.
title
=
getString
(
R
.
string
.
fragment_room_list_member_list_title
,
total
)
activity
?
.
title
=
getString
(
R
.
string
.
fragment_room_list_member_list_title
,
total
)
if
(
recyclerView
.
adapter
==
null
)
{
recyclerView
.
adapter
=
RoomMemberListAdapter
(
dataSet
,
hostname
,
context
)
recyclerView
.
adapter
=
RoomMemberListAdapter
(
dataSet
,
hostname
,
context
!!
)
val
linearLayoutManager
=
LinearLayoutManager
(
context
,
LinearLayoutManager
.
VERTICAL
,
false
)
recyclerView
.
layoutManager
=
linearLayoutManager
if
(
dataSet
.
size
>=
50
)
{
...
...
app/src/main/java/chat/rocket/android/fragment/oauth/OAuthPresenter.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
fragment
.
oauth
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
org.json.JSONObject
;
import
chat.rocket.android.BackgroundLooper
;
...
...
@@ -10,6 +9,7 @@ import chat.rocket.android.helper.Logger;
import
chat.rocket.android.helper.TextUtils
;
import
chat.rocket.android.shared.BasePresenter
;
import
chat.rocket.core.repositories.LoginServiceConfigurationRepository
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
public
class
OAuthPresenter
extends
BasePresenter
<
OAuthContract
.
View
>
implements
OAuthContract
.
Presenter
{
...
...
app/src/main/java/chat/rocket/android/fragment/server_config/LoginContract.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
fragment
.
server_config
;
import
java.util.List
;
import
chat.rocket.android.shared.BaseContract
;
import
chat.rocket.core.models.LoginServiceConfiguration
;
...
...
app/src/main/java/chat/rocket/android/fragment/server_config/LoginFragment.java
View file @
5bbd3f7f
...
...
@@ -11,6 +11,7 @@ import android.widget.TextView;
import
java.util.HashMap
;
import
java.util.List
;
import
chat.rocket.android.R
;
import
chat.rocket.android.api.MethodCallHelper
;
import
chat.rocket.android.layouthelper.oauth.OAuthProviderInfo
;
...
...
app/src/main/java/chat/rocket/android/fragment/server_config/LoginPresenter.java
View file @
5bbd3f7f
...
...
@@ -3,7 +3,6 @@ package chat.rocket.android.fragment.server_config;
import
android.support.annotation.NonNull
;
import
com.hadisatrio.optional.Optional
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
bolts.Task
;
import
chat.rocket.android.BackgroundLooper
;
...
...
@@ -16,6 +15,7 @@ import chat.rocket.core.PublicSettingsConstants;
import
chat.rocket.core.models.PublicSetting
;
import
chat.rocket.core.repositories.LoginServiceConfigurationRepository
;
import
chat.rocket.core.repositories.PublicSettingRepository
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
public
class
LoginPresenter
extends
BasePresenter
<
LoginContract
.
View
>
implements
LoginContract
.
Presenter
{
...
...
@@ -85,7 +85,7 @@ public class LoginPresenter extends BasePresenter<LoginContract.View>
}
}
return
null
;
});
}
,
Task
.
UI_THREAD_EXECUTOR
);
}
private
Task
<
Void
>
call
(
String
username
,
String
password
,
Optional
<
PublicSetting
>
optional
)
{
...
...
app/src/main/java/chat/rocket/android/fragment/server_config/RetryLoginPresenter.java
View file @
5bbd3f7f
...
...
@@ -3,7 +3,6 @@ package chat.rocket.android.fragment.server_config;
import
android.support.annotation.NonNull
;
import
com.hadisatrio.optional.Optional
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
chat.rocket.android.BackgroundLooper
;
import
chat.rocket.android.api.MethodCallHelper
;
...
...
@@ -12,6 +11,7 @@ import chat.rocket.android.helper.TextUtils;
import
chat.rocket.android.shared.BasePresenter
;
import
chat.rocket.core.interactors.SessionInteractor
;
import
chat.rocket.core.models.Session
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
public
class
RetryLoginPresenter
extends
BasePresenter
<
RetryLoginContract
.
View
>
implements
RetryLoginContract
.
Presenter
{
...
...
app/src/main/java/chat/rocket/android/fragment/server_config/TwoStepAuthPresenter.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
fragment
.
server_config
;
import
bolts.Task
;
import
chat.rocket.android.api.MethodCallHelper
;
import
chat.rocket.android.shared.BasePresenter
;
...
...
@@ -29,6 +30,6 @@ public class TwoStepAuthPresenter extends BasePresenter<TwoStepAuthContract.View
view
.
showError
(
task
.
getError
().
getMessage
());
}
return
null
;
});
}
,
Task
.
UI_THREAD_EXECUTOR
);
}
}
app/src/main/java/chat/rocket/android/fragment/sidebar/SidebarMainContract.java
View file @
5bbd3f7f
...
...
@@ -2,13 +2,14 @@ package chat.rocket.android.fragment.sidebar;
import
android.support.annotation.NonNull
;
import
bolts.Continuation
;
import
chat.rocket.core.models.RoomSidebar
;
import
io.reactivex.Flowable
;
import
java.util.List
;
import
bolts.Continuation
;
import
chat.rocket.android.shared.BaseContract
;
import
chat.rocket.core.models.RoomSidebar
;
import
chat.rocket.core.models.Spotlight
;
import
chat.rocket.core.models.User
;
import
io.reactivex.Flowable
;
public
interface
SidebarMainContract
{
...
...
app/src/main/java/chat/rocket/android/fragment/sidebar/SidebarMainFragment.java
View file @
5bbd3f7f
...
...
@@ -151,6 +151,7 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain
adapter
.
setOnItemClickListener
(
new
RoomListAdapter
.
OnItemClickListener
()
{
@Override
public
void
onItemClick
(
RoomSidebar
roomSidebar
)
{
searchView
.
setQuery
(
null
,
false
);
searchView
.
clearFocus
();
presenter
.
onRoomSelected
(
roomSidebar
);
}
...
...
app/src/main/java/chat/rocket/android/fragment/sidebar/dialog/AddDirectMessageDialogFragment.java
View file @
5bbd3f7f
...
...
@@ -5,11 +5,9 @@ import android.os.Bundle;
import
android.view.View
;
import
android.widget.AutoCompleteTextView
;
import
android.widget.TextView
;
import
com.hadisatrio.optional.Optional
;
import
com.jakewharton.rxbinding2.widget.RxTextView
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.reactivex.disposables.CompositeDisposable
;
import
io.realm.Case
;
import
bolts.Task
;
import
chat.rocket.android.BackgroundLooper
;
...
...
@@ -20,11 +18,14 @@ import chat.rocket.android.helper.Logger;
import
chat.rocket.android.helper.TextUtils
;
import
chat.rocket.android.layouthelper.sidebar.dialog.SuggestUserAdapter
;
import
chat.rocket.core.interactors.SessionInteractor
;
import
chat.rocket.persistence.realm.models.ddp.RealmUser
;
import
chat.rocket.persistence.realm.RealmAutoCompleteAdapter
;
import
chat.rocket.persistence.realm.models.ddp.RealmUser
;
import
chat.rocket.persistence.realm.repositories.RealmServerInfoRepository
;
import
chat.rocket.persistence.realm.repositories.RealmSessionRepository
;
import
chat.rocket.persistence.realm.repositories.RealmUserRepository
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.reactivex.disposables.CompositeDisposable
;
import
io.realm.Case
;
/**
* add Direct RealmMessage.
...
...
app/src/main/java/chat/rocket/android/helper/AbsoluteUrlHelper.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
helper
;
import
com.hadisatrio.optional.Optional
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
import
chat.rocket.android.fragment.chatroom.RocketChatAbsoluteUrl
;
import
chat.rocket.core.interactors.SessionInteractor
;
import
chat.rocket.core.repositories.ServerInfoRepository
;
import
chat.rocket.core.repositories.UserRepository
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
public
class
AbsoluteUrlHelper
{
...
...
app/src/main/java/chat/rocket/android/helper/DateTime.java
View file @
5bbd3f7f
...
...
@@ -6,9 +6,11 @@ import android.text.format.DateFormat;
import
java.text.ParseException
;
import
java.text.SimpleDateFormat
;
import
java.util.Calendar
;
import
java.util.Date
;
import
java.util.GregorianCalendar
;
import
java.util.Locale
;
import
java.util.TimeZone
;
import
chat.rocket.android.log.RCLog
;
/**
...
...
@@ -55,7 +57,7 @@ public class DateTime {
case
DAY:
return
DAY_FORMAT
.
format
(
cal
.
getTime
());
case
DATE:
return
DATE_FORMAT
.
f
ormat
(
cal
.
getTime
());
return
getDateF
ormat
(
cal
.
getTime
());
case
TIME:
return
TIME_FORMAT
.
format
(
cal
.
getTime
());
case
DATE_TIME:
...
...
@@ -80,6 +82,22 @@ public class DateTime {
}
}
private
static
String
getDateFormat
(
Date
dateTime
)
{
Calendar
calendar
=
Calendar
.
getInstance
();
calendar
.
setTime
(
dateTime
);
Calendar
today
=
Calendar
.
getInstance
();
Calendar
yesterday
=
Calendar
.
getInstance
();
yesterday
.
add
(
Calendar
.
DATE
,
-
1
);
if
(
calendar
.
get
(
Calendar
.
YEAR
)
==
today
.
get
(
Calendar
.
YEAR
)
&&
calendar
.
get
(
Calendar
.
DAY_OF_YEAR
)
==
today
.
get
(
Calendar
.
DAY_OF_YEAR
))
{
return
"Today"
;
}
else
if
(
calendar
.
get
(
Calendar
.
YEAR
)
==
yesterday
.
get
(
Calendar
.
YEAR
)
&&
calendar
.
get
(
Calendar
.
DAY_OF_YEAR
)
==
yesterday
.
get
(
Calendar
.
DAY_OF_YEAR
))
{
return
"Yesterday"
;
}
else
{
return
DATE_FORMAT
.
format
(
dateTime
);
}
}
/**
* parse datetime string to ms.
*/
...
...
app/src/main/java/chat/rocket/android/helper/FileUploadHelper.java
View file @
5bbd3f7f
...
...
@@ -8,16 +8,18 @@ import android.os.ParcelFileDescriptor;
import
android.provider.OpenableColumns
;
import
android.support.annotation.Nullable
;
import
android.webkit.MimeTypeMap
;
import
org.json.JSONObject
;
import
java.io.FileNotFoundException
;
import
java.io.IOException
;
import
java.util.UUID
;
import
chat.rocket.android.log.RCLog
;
import
chat.rocket.core.SyncState
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.persistence.realm.models.ddp.RealmPublicSetting
;
import
chat.rocket.persistence.realm.models.internal.FileUploading
;
import
chat.rocket.persistence.realm.RealmHelper
;
/**
* utility class for uploading file.
...
...
app/src/main/java/chat/rocket/android/helper/GcmPushSettingHelper.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
helper
;
import
io.realm.Realm
;
import
io.realm.RealmResults
;
import
java.util.List
;
import
chat.rocket.persistence.realm.models.ddp.RealmPublicSetting
;
import
chat.rocket.core.PublicSettingsConstants
;
import
chat.rocket.persistence.realm.models.ddp.RealmPublicSetting
;
import
io.realm.Realm
;
import
io.realm.RealmResults
;
/**
* utility class for getting value comprehensibly from public settings list.
...
...
app/src/main/java/chat/rocket/android/helper/RxHelper.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
helper
;
import
java.util.concurrent.TimeUnit
;
import
rx.Observable
;
import
rx.functions.Func1
;
import
io.reactivex.Flowable
;
import
io.reactivex.functions.Function
;
/**
* Rx operator and so on.
*/
public
class
RxHelper
{
public
static
Func
1
<
Observable
<?
extends
Throwable
>,
Observ
able
<?>>
exponentialBackoff
(
public
static
Func
tion
<
Flowable
<?
extends
Throwable
>,
Flow
able
<?>>
exponentialBackoff
(
int
maxRetryCount
,
long
base
,
TimeUnit
unit
)
{
// ref: https://github.com/ReactiveX/RxJava/blob/a8ba158839b67246a742b6f1531995ffd7545c08/src/main/java/io/reactivex/Observable.java#L9601
return
attempts
->
attempts
.
zipWith
(
Observ
able
.
range
(
0
,
maxRetryCount
),
(
error
,
retryCount
)
->
retryCount
)
.
flatMap
(
retryCount
->
Observ
able
.
timer
(
base
*
(
long
)
Math
.
pow
(
2
,
retryCount
),
unit
));
.
zipWith
(
Flow
able
.
range
(
0
,
maxRetryCount
),
(
error
,
retryCount
)
->
retryCount
)
.
flatMap
(
retryCount
->
Flow
able
.
timer
(
base
*
(
long
)
Math
.
pow
(
2
,
retryCount
),
unit
));
}
}
app/src/main/java/chat/rocket/android/helper/ServerPolicyApiValidationHelper.java
View file @
5bbd3f7f
...
...
@@ -2,9 +2,8 @@ package chat.rocket.android.helper;
import
android.support.annotation.NonNull
;
import
io.reactivex.Flowable
;
import
chat.rocket.android.api.rest.ServerPolicyApi
;
import
io.reactivex.Flowable
;
public
class
ServerPolicyApiValidationHelper
{
...
...
app/src/main/java/chat/rocket/android/helper/ServerPolicyHelper.java
View file @
5bbd3f7f
...
...
@@ -2,9 +2,10 @@ package chat.rocket.android.helper;
import
android.support.annotation.NonNull
;
import
io.reactivex.Flowable
;
import
org.json.JSONObject
;
import
io.reactivex.Flowable
;
public
class
ServerPolicyHelper
{
private
static
final
String
DEFAULT_HOST
=
".rocket.chat"
;
...
...
@@ -12,7 +13,7 @@ public class ServerPolicyHelper {
public
static
String
enforceHostname
(
String
hostname
)
{
if
(
hostname
==
null
)
{
return
"
demo
.rocket.chat"
;
return
"
open
.rocket.chat"
;
}
return
removeTrailingSlash
(
removeProtocol
(
enforceDefaultHost
(
hostname
)));
...
...
app/src/main/java/chat/rocket/android/layouthelper/chatroom/AbstractMessageViewHolder.java
View file @
5bbd3f7f
...
...
@@ -4,6 +4,7 @@ import android.support.annotation.Nullable;
import
android.view.View
;
import
android.widget.ImageView
;
import
android.widget.TextView
;
import
chat.rocket.android.R
;
import
chat.rocket.android.helper.DateTime
;
import
chat.rocket.android.helper.TextUtils
;
...
...
@@ -44,7 +45,8 @@ public abstract class AbstractMessageViewHolder extends ModelViewHolder<PairedMe
* bind the view model.
*/
public
final
void
bind
(
PairedMessage
pairedMessage
,
boolean
autoloadImages
)
{
if
(
pairedMessage
.
target
.
getSyncState
()
==
SyncState
.
FAILED
)
{
if
(
pairedMessage
.
target
.
getSyncState
()
==
SyncState
.
FAILED
||
pairedMessage
.
target
.
getSyncState
()
==
SyncState
.
DELETE_FAILED
)
{
errorImageView
.
setVisibility
(
View
.
VISIBLE
);
}
else
{
errorImageView
.
setVisibility
(
View
.
GONE
);
...
...
app/src/main/java/chat/rocket/android/layouthelper/chatroom/MessageListAdapter.java
View file @
5bbd3f7f
...
...
@@ -7,6 +7,7 @@ import android.view.View;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.List
;
import
chat.rocket.android.R
;
import
chat.rocket.android.helper.TextUtils
;
import
chat.rocket.android.layouthelper.ExtModelListAdapter
;
...
...
app/src/main/java/chat/rocket/android/layouthelper/chatroom/MessageNormalViewHolder.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
layouthelper
.
chatroom
;
import
android.view.View
;
import
chat.rocket.android.R
;
import
chat.rocket.android.renderer.MessageRenderer
;
import
chat.rocket.android.widget.AbsoluteUrl
;
...
...
app/src/main/java/chat/rocket/android/layouthelper/chatroom/MessagePopup.java
View file @
5bbd3f7f
...
...
@@ -37,7 +37,8 @@ public class MessagePopup {
private
static
final
Action
QUOTE_ACTION_INFO
=
new
Action
(
"Quote"
,
null
,
true
);
private
static
final
Action
EDIT_ACTION_INFO
=
new
Action
(
"Edit"
,
null
,
true
);
private
static
final
Action
COPY_ACTION_INFO
=
new
Action
(
"Copy"
,
null
,
true
);
private
final
List
<
Action
>
defaultActions
=
new
ArrayList
<>(
4
);
private
static
final
Action
DELETE_ACTION_INFO
=
new
Action
(
"Delete"
,
null
,
false
);
private
final
List
<
Action
>
defaultActions
=
new
ArrayList
<>(
5
);
private
final
List
<
Action
>
otherActions
=
new
ArrayList
<>();
private
Message
message
;
private
CompositeDisposable
compositeDisposable
=
new
CompositeDisposable
();
...
...
@@ -73,6 +74,7 @@ public class MessagePopup {
.
subscribe
(
pair
->
{
EDIT_ACTION_INFO
.
allowed
=
pair
.
second
;
DELETE_ACTION_INFO
.
allowed
=
pair
.
second
;
List
<
Action
>
allActions
=
singleton
.
defaultActions
;
List
<
Action
>
allowedActions
=
new
ArrayList
<>(
3
);
for
(
int
i
=
0
;
i
<
allActions
.
size
();
i
++)
{
...
...
@@ -110,6 +112,7 @@ public class MessagePopup {
singleton
.
defaultActions
.
add
(
QUOTE_ACTION_INFO
);
singleton
.
defaultActions
.
add
(
EDIT_ACTION_INFO
);
singleton
.
defaultActions
.
add
(
COPY_ACTION_INFO
);
singleton
.
defaultActions
.
add
(
DELETE_ACTION_INFO
);
}
public
static
MessagePopup
take
(
Message
message
)
{
...
...
@@ -163,6 +166,11 @@ public class MessagePopup {
return
singleton
;
}
public
MessagePopup
setDeleteAction
(
ActionListener
actionListener
)
{
DELETE_ACTION_INFO
.
actionListener
=
actionListener
;
return
singleton
;
}
public
MessagePopup
setQuoteAction
(
ActionListener
actionListener
)
{
QUOTE_ACTION_INFO
.
actionListener
=
actionListener
;
return
singleton
;
...
...
app/src/main/java/chat/rocket/android/layouthelper/chatroom/list/RoomFileListAdapter.kt
View file @
5bbd3f7f
...
...
@@ -7,10 +7,13 @@ import android.view.ViewGroup
import
android.widget.TextView
import
chat.rocket.android.R
import
chat.rocket.android.helper.DateTime
import
chat.rocket.android.helper.Logger
import
chat.rocket.android.log.RCLog
import
chat.rocket.android.widget.message.RocketChatMessageAttachmentsLayout
import
chat.rocket.core.models.Attachment
import
kotlinx.android.synthetic.main.day.view.*
import
kotlinx.android.synthetic.main.item_room_file.view.*
import
java.lang.IllegalArgumentException
import
java.sql.Timestamp
/**
...
...
@@ -26,8 +29,16 @@ class RoomFileListAdapter(private var dataSet: List<Attachment>) : RecyclerView.
override
fun
onBindViewHolder
(
holder
:
ViewHolder
,
position
:
Int
)
{
val
attachment
=
dataSet
[
position
]
holder
.
newDay
.
text
=
DateTime
.
fromEpocMs
(
Timestamp
.
valueOf
(
attachment
.
timestamp
).
time
,
DateTime
.
Format
.
DATE
)
holder
.
attachment
.
appendAttachmentView
(
attachment
,
true
,
false
)
val
timestamp
:
Timestamp
?
try
{
timestamp
=
Timestamp
.
valueOf
(
attachment
.
timestamp
)
// If we don't have a timestamp we can parse let's be safe and stop here.
holder
.
newDay
.
text
=
DateTime
.
fromEpocMs
(
timestamp
.
time
,
DateTime
.
Format
.
DATE
)
holder
.
attachment
.
appendAttachmentView
(
attachment
,
true
,
false
)
}
catch
(
e
:
IllegalArgumentException
)
{
RCLog
.
e
(
e
)
Logger
.
report
(
e
)
}
}
override
fun
getItemCount
():
Int
=
dataSet
.
size
...
...
app/src/main/java/chat/rocket/android/layouthelper/chatroom/list/RoomUserAdapter.java
View file @
5bbd3f7f
...
...
@@ -7,13 +7,14 @@ import android.view.View;
import
android.view.ViewGroup
;
import
java.util.List
;
import
chat.rocket.android.R
;
import
chat.rocket.android.helper.TextUtils
;
import
chat.rocket.android.renderer.UserRenderer
;
import
chat.rocket.android.widget.AbsoluteUrl
;
import
chat.rocket.core.models.User
;
import
chat.rocket.persistence.realm.models.ddp.RealmUser
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.
android.renderer.UserRender
er
;
import
chat.rocket.
persistence.realm.models.ddp.RealmUs
er
;
/**
* RecyclerView adapter for UsersOfRooms.
...
...
app/src/main/java/chat/rocket/android/layouthelper/chatroom/roomlist/ChannelRoomListHeader.java
View file @
5bbd3f7f
...
...
@@ -2,9 +2,10 @@ package chat.rocket.android.layouthelper.chatroom.roomlist;
import
android.support.annotation.NonNull
;
import
chat.rocket.core.models.RoomSidebar
;
import
java.util.List
;
import
chat.rocket.core.models.Room
;
import
chat.rocket.core.models.RoomSidebar
;
public
class
ChannelRoomListHeader
implements
RoomListHeader
{
...
...
app/src/main/java/chat/rocket/android/layouthelper/chatroom/roomlist/DirectMessageRoomListHeader.java
View file @
5bbd3f7f
...
...
@@ -2,9 +2,10 @@ package chat.rocket.android.layouthelper.chatroom.roomlist;
import
android.support.annotation.NonNull
;
import
chat.rocket.core.models.RoomSidebar
;
import
java.util.List
;
import
chat.rocket.core.models.Room
;
import
chat.rocket.core.models.RoomSidebar
;
public
class
DirectMessageRoomListHeader
implements
RoomListHeader
{
...
...
app/src/main/java/chat/rocket/android/layouthelper/chatroom/roomlist/FavoriteRoomListHeader.java
View file @
5bbd3f7f
...
...
@@ -2,9 +2,10 @@ package chat.rocket.android.layouthelper.chatroom.roomlist;
import
android.support.annotation.NonNull
;
import
chat.rocket.core.models.RoomSidebar
;
import
java.util.List
;
import
chat.rocket.core.models.RoomSidebar
;
public
class
FavoriteRoomListHeader
implements
RoomListHeader
{
private
final
String
title
;
...
...
app/src/main/java/chat/rocket/android/layouthelper/chatroom/roomlist/RoomListAdapter.java
View file @
5bbd3f7f
...
...
@@ -5,14 +5,15 @@ import android.support.v7.widget.RecyclerView;
import
android.view.LayoutInflater
;
import
android.view.ViewGroup
;
import
chat.rocket.core.models.RoomSidebar
;
import
chat.rocket.core.models.Spotlight
;
import
java.util.Collections
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
chat.rocket.android.R
;
import
chat.rocket.android.widget.internal.RoomListItemView
;
import
chat.rocket.core.models.RoomSidebar
;
import
chat.rocket.core.models.Spotlight
;
public
class
RoomListAdapter
extends
RecyclerView
.
Adapter
<
RecyclerView
.
ViewHolder
>
{
...
...
app/src/main/java/chat/rocket/android/layouthelper/chatroom/roomlist/RoomListHeader.java
View file @
5bbd3f7f
...
...
@@ -2,9 +2,10 @@ package chat.rocket.android.layouthelper.chatroom.roomlist;
import
android.support.annotation.NonNull
;
import
chat.rocket.core.models.RoomSidebar
;
import
java.util.List
;
import
chat.rocket.core.models.RoomSidebar
;
public
interface
RoomListHeader
{
String
getTitle
();
...
...
app/src/main/java/chat/rocket/android/layouthelper/chatroom/roomlist/UnreadRoomListHeader.java
View file @
5bbd3f7f
...
...
@@ -2,9 +2,10 @@ package chat.rocket.android.layouthelper.chatroom.roomlist;
import
android.support.annotation.NonNull
;
import
chat.rocket.core.models.RoomSidebar
;
import
java.util.List
;
import
chat.rocket.core.models.RoomSidebar
;
public
class
UnreadRoomListHeader
implements
RoomListHeader
{
private
final
String
title
;
...
...
app/src/main/java/chat/rocket/android/layouthelper/oauth/OAuthProviderInfo.java
View file @
5bbd3f7f
...
...
@@ -3,6 +3,7 @@ package chat.rocket.android.layouthelper.oauth;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.List
;
import
chat.rocket.android.R
;
import
chat.rocket.android.fragment.oauth.AbstractOAuthFragment
;
import
chat.rocket.android.fragment.oauth.FacebookOAuthFragment
;
...
...
app/src/main/java/chat/rocket/android/layouthelper/sidebar/dialog/SuggestUserAdapter.java
View file @
5bbd3f7f
...
...
@@ -5,11 +5,12 @@ import android.view.View;
import
java.util.Iterator
;
import
java.util.List
;
import
chat.rocket.android.R
;
import
chat.rocket.android.renderer.UserRenderer
;
import
chat.rocket.android.widget.AbsoluteUrl
;
import
chat.rocket.persistence.realm.models.ddp.RealmUser
;
import
chat.rocket.persistence.realm.RealmAutoCompleteAdapter
;
import
chat.rocket.
android.renderer.UserRender
er
;
import
chat.rocket.
persistence.realm.models.ddp.RealmUs
er
;
/**
* adapter to suggest user names.
...
...
app/src/main/java/chat/rocket/android/push/BackgroundActionButtonHandler.java
View file @
5bbd3f7f
...
...
@@ -5,8 +5,8 @@ import android.content.BroadcastReceiver;
import
android.content.Context
;
import
android.content.Intent
;
import
android.os.Bundle
;
import
android.util.Log
;
import
android.support.v4.app.RemoteInput
;
import
android.util.Log
;
import
chat.rocket.android.push.gcm.GCMIntentService
;
...
...
app/src/main/java/chat/rocket/android/push/PushManager.kt
0 → 100644
View file @
5bbd3f7f
package
chat.rocket.android.push
import
android.app.Notification
import
android.app.NotificationChannel
import
android.app.NotificationManager
import
android.app.PendingIntent
import
android.content.BroadcastReceiver
import
android.content.Context
import
android.content.Intent
import
android.graphics.drawable.Icon
import
android.os.Build
import
android.os.Bundle
import
android.support.annotation.RequiresApi
import
android.support.v4.app.NotificationCompat
import
android.support.v4.app.NotificationManagerCompat
import
android.support.v4.app.RemoteInput
import
android.text.Html
import
android.text.Spanned
import
android.util.Log
import
chat.rocket.android.BackgroundLooper
import
chat.rocket.android.BuildConfig
import
chat.rocket.android.R
import
chat.rocket.android.RocketChatCache
import
chat.rocket.android.activity.MainActivity
import
chat.rocket.android.helper.Logger
import
chat.rocket.core.interactors.MessageInteractor
import
chat.rocket.core.models.Room
import
chat.rocket.core.models.User
import
chat.rocket.persistence.realm.repositories.RealmMessageRepository
import
chat.rocket.persistence.realm.repositories.RealmRoomRepository
import
chat.rocket.persistence.realm.repositories.RealmUserRepository
import
io.reactivex.Single
import
io.reactivex.android.schedulers.AndroidSchedulers
import
io.reactivex.functions.BiFunction
import
okhttp3.HttpUrl
import
org.json.JSONObject
import
java.io.Serializable
import
java.util.*
import
java.util.concurrent.atomic.AtomicInteger
import
kotlin.collections.HashMap
typealias
TupleRoomUser
=
Pair
<
Room
,
User
>
typealias
TupleGroupIdMessageCount
=
Pair
<
Int
,
AtomicInteger
>
object
PushManager
{
const
val
EXTRA_NOT_ID
=
"chat.rocket.android.EXTRA_NOT_ID"
const
val
EXTRA_HOSTNAME
=
"chat.rocket.android.EXTRA_HOSTNAME"
const
val
EXTRA_PUSH_MESSAGE
=
"chat.rocket.android.EXTRA_PUSH_MESSAGE"
const
val
EXTRA_ROOM_ID
=
"chat.rocket.android.EXTRA_ROOM_ID"
private
const
val
REPLY_LABEL
=
"REPLY"
private
const
val
REMOTE_INPUT_REPLY
=
"REMOTE_INPUT_REPLY"
// Notifications received from the same server are grouped in a single bundled notification.
// This map associates a host to a group id.
private
val
groupMap
=
HashMap
<
String
,
TupleGroupIdMessageCount
>()
// Map a hostname to a list of push messages that pertain to it.
private
val
hostToPushMessageList
=
HashMap
<
String
,
MutableList
<
PushMessage
>>()
private
val
randomizer
=
Random
()
/**
* Handles a receiving push by creating and displaying an appropriate notification based
* on the *data* param bundle received.
*/
@Synchronized
fun
handle
(
context
:
Context
,
data
:
Bundle
)
{
val
appContext
=
context
.
applicationContext
val
message
=
data
[
"message"
]
as
String
?
val
image
=
data
[
"image"
]
as
String
?
val
ejson
=
data
[
"ejson"
]
as
String
?
val
notId
=
data
[
"notId"
]
as
String
?
?:
randomizer
.
nextInt
().
toString
()
val
style
=
data
[
"style"
]
as
String
?
val
summaryText
=
data
[
"summaryText"
]
as
String
?
val
count
=
data
[
"count"
]
as
String
?
val
title
=
data
[
"title"
]
as
String
?
if
(
ejson
==
null
||
message
==
null
||
title
==
null
)
{
return
}
val
lastPushMessage
=
PushMessage
(
title
,
message
,
image
,
ejson
,
count
,
notId
,
summaryText
,
style
)
// We should use Timber here
if
(
BuildConfig
.
DEBUG
)
{
Log
.
d
(
PushMessage
::
class
.
java
.
simpleName
,
lastPushMessage
.
toString
())
}
showNotification
(
appContext
,
lastPushMessage
)
}
/**
* Clear all messages received to a given host the user is signed-in.
*/
fun
clearNotificationsByHost
(
host
:
String
)
{
hostToPushMessageList
.
remove
(
host
)
}
/**
* Remove a notification solely by it's unique id.
*/
fun
clearNotificationsByNotificationId
(
notificationId
:
Int
)
{
if
(
hostToPushMessageList
.
isNotEmpty
())
{
for
(
entry
in
hostToPushMessageList
.
entries
)
{
entry
.
value
.
removeAll
{
it
.
notificationId
.
toInt
()
==
notificationId
}
}
}
}
/**
* Clear notifications by the host they belong to and its unique id.
*/
fun
clearNotificationsByHostAndNotificationId
(
host
:
String
?,
notificationId
:
Int
?)
{
if
(
host
==
null
||
notificationId
==
null
)
{
return
}
if
(
hostToPushMessageList
.
isNotEmpty
())
{
val
notifications
=
hostToPushMessageList
[
host
]
notifications
?.
let
{
notifications
.
removeAll
{
it
.
notificationId
.
toInt
()
==
notificationId
}
}
}
}
private
fun
isAndroidVersionAtLeast
(
minVersion
:
Int
)
=
Build
.
VERSION
.
SDK_INT
>=
minVersion
private
fun
getGroupForHost
(
host
:
String
):
TupleGroupIdMessageCount
{
val
size
=
groupMap
.
size
var
group
=
groupMap
.
get
(
host
)
if
(
group
==
null
)
{
group
=
TupleGroupIdMessageCount
(
size
+
1
,
AtomicInteger
(
0
))
groupMap
.
put
(
host
,
group
)
}
return
group
}
internal
fun
showNotification
(
context
:
Context
,
lastPushMessage
:
PushMessage
)
{
if
(
lastPushMessage
.
host
==
null
||
lastPushMessage
.
message
==
null
||
lastPushMessage
.
title
==
null
)
{
return
}
val
manager
:
NotificationManager
=
context
.
getSystemService
(
Context
.
NOTIFICATION_SERVICE
)
as
NotificationManager
val
notId
=
lastPushMessage
.
notificationId
.
toInt
()
val
host
=
lastPushMessage
.
host
val
groupTuple
=
getGroupForHost
(
host
)
groupTuple
.
second
.
incrementAndGet
()
val
notIdListForHostname
:
MutableList
<
PushMessage
>?
=
hostToPushMessageList
.
get
(
host
)
if
(
notIdListForHostname
==
null
)
{
hostToPushMessageList
.
put
(
host
,
arrayListOf
(
lastPushMessage
))
}
else
{
notIdListForHostname
.
add
(
0
,
lastPushMessage
)
}
if
(
isAndroidVersionAtLeast
(
Build
.
VERSION_CODES
.
N
))
{
val
notification
=
createSingleNotificationForNougatAndAbove
(
context
,
lastPushMessage
)
val
groupNotification
=
createGroupNotificationForNougatAndAbove
(
context
,
lastPushMessage
)
notification
?.
let
{
manager
.
notify
(
notId
,
notification
)
}
groupNotification
?.
let
{
manager
.
notify
(
groupTuple
.
first
,
groupNotification
)
}
}
else
{
val
notification
=
createSingleNotification
(
context
,
lastPushMessage
)
val
pushMessageList
=
hostToPushMessageList
.
get
(
host
)
notification
?.
let
{
NotificationManagerCompat
.
from
(
context
).
notify
(
notId
,
notification
)
}
pushMessageList
?.
let
{
if
(
pushMessageList
.
size
>
1
)
{
val
groupNotification
=
createGroupNotification
(
context
,
lastPushMessage
)
groupNotification
?.
let
{
NotificationManagerCompat
.
from
(
context
).
notify
(
groupTuple
.
first
,
groupNotification
)
}
}
}
}
}
internal
fun
createGroupNotification
(
context
:
Context
,
lastPushMessage
:
PushMessage
):
Notification
?
{
with
(
lastPushMessage
)
{
if
(
host
==
null
||
message
==
null
||
title
==
null
)
{
return
null
}
val
id
=
lastPushMessage
.
notificationId
.
toInt
()
val
contentIntent
=
getContentIntent
(
context
,
id
,
lastPushMessage
)
val
deleteIntent
=
getDismissIntent
(
context
,
lastPushMessage
)
val
builder
=
NotificationCompat
.
Builder
(
context
)
.
setWhen
(
createdAt
)
.
setContentTitle
(
title
.
fromHtml
())
.
setContentText
(
message
.
fromHtml
())
.
setGroup
(
host
)
.
setGroupSummary
(
true
)
.
setContentIntent
(
contentIntent
)
.
setDeleteIntent
(
deleteIntent
)
.
setMessageNotification
()
val
subText
=
RocketChatCache
(
context
).
getHostSiteName
(
host
)
if
(
subText
.
isNotEmpty
())
{
builder
.
setSubText
(
subText
)
}
if
(
style
==
null
||
style
==
"inbox"
)
{
val
pushMessageList
=
hostToPushMessageList
.
get
(
host
)
pushMessageList
?.
let
{
val
messageCount
=
pushMessageList
.
size
val
summary
=
summaryText
?.
replace
(
"%n%"
,
messageCount
.
toString
())
?.
fromHtml
()
?:
"$messageCount new messages"
builder
.
setNumber
(
messageCount
)
if
(
messageCount
>
1
)
{
val
firstPush
=
pushMessageList
[
0
]
val
singleConversation
=
pushMessageList
.
filter
{
firstPush
.
sender
?.
username
!=
it
.
sender
?.
username
}.
isEmpty
()
val
inbox
=
NotificationCompat
.
InboxStyle
()
.
setBigContentTitle
(
if
(
singleConversation
)
title
else
summary
)
for
(
push
in
pushMessageList
)
{
if
(
singleConversation
)
{
inbox
.
addLine
(
push
.
message
)
}
else
{
inbox
.
addLine
(
"<font color='black'>${push.title}</font> <font color='gray'>${push.message}</font>"
.
fromHtml
())
}
}
builder
.
setStyle
(
inbox
)
}
else
{
val
firstMsg
=
pushMessageList
[
0
]
if
(
firstMsg
.
host
==
null
||
firstMsg
.
message
==
null
||
firstMsg
.
title
==
null
)
{
return
null
}
val
bigText
=
NotificationCompat
.
BigTextStyle
()
.
bigText
(
firstMsg
.
message
.
fromHtml
())
.
setBigContentTitle
(
firstMsg
.
title
.
fromHtml
())
builder
.
setStyle
(
bigText
)
}
}
}
else
{
val
bigText
=
NotificationCompat
.
BigTextStyle
()
.
bigText
(
message
.
fromHtml
())
.
setBigContentTitle
(
title
.
fromHtml
())
builder
.
setStyle
(
bigText
)
}
return
builder
.
build
()
}
}
@RequiresApi
(
Build
.
VERSION_CODES
.
N
)
internal
fun
createGroupNotificationForNougatAndAbove
(
context
:
Context
,
lastPushMessage
:
PushMessage
):
Notification
?
{
with
(
lastPushMessage
)
{
if
(
host
==
null
||
message
==
null
||
title
==
null
)
{
return
null
}
val
manager
:
NotificationManager
=
context
.
getSystemService
(
Context
.
NOTIFICATION_SERVICE
)
as
NotificationManager
val
id
=
notificationId
.
toInt
()
val
contentIntent
=
getContentIntent
(
context
,
id
,
lastPushMessage
,
grouped
=
true
)
val
deleteIntent
=
getDismissIntent
(
context
,
lastPushMessage
)
val
builder
=
Notification
.
Builder
(
context
)
.
setWhen
(
createdAt
)
.
setContentTitle
(
title
.
fromHtml
())
.
setContentText
(
message
.
fromHtml
())
.
setGroup
(
host
)
.
setGroupSummary
(
true
)
.
setContentIntent
(
contentIntent
)
.
setDeleteIntent
(
deleteIntent
)
.
setMessageNotification
(
context
)
if
(
isAndroidVersionAtLeast
(
Build
.
VERSION_CODES
.
O
))
{
builder
.
setChannelId
(
host
)
val
groupChannel
=
NotificationChannel
(
host
,
host
,
NotificationManager
.
IMPORTANCE_HIGH
)
groupChannel
.
lockscreenVisibility
=
Notification
.
VISIBILITY_PUBLIC
groupChannel
.
enableLights
(
false
)
groupChannel
.
enableVibration
(
true
)
groupChannel
.
setShowBadge
(
true
)
manager
.
createNotificationChannel
(
groupChannel
)
}
val
subText
=
RocketChatCache
(
context
).
getHostSiteName
(
host
)
if
(
subText
.
isNotEmpty
())
{
builder
.
setSubText
(
subText
)
}
if
(
style
==
null
||
style
==
"inbox"
)
{
val
pushMessageList
=
hostToPushMessageList
.
get
(
host
)
pushMessageList
?.
let
{
val
count
=
pushMessageList
.
filter
{
it
.
title
==
title
}.
size
builder
.
setContentTitle
(
getTitle
(
count
,
title
))
val
inbox
=
Notification
.
InboxStyle
()
.
setBigContentTitle
(
getTitle
(
count
,
title
))
for
(
push
in
pushMessageList
)
{
inbox
.
addLine
(
push
.
message
)
}
builder
.
setStyle
(
inbox
)
}
}
else
{
val
bigText
=
Notification
.
BigTextStyle
()
.
bigText
(
message
.
fromHtml
())
.
setBigContentTitle
(
title
.
fromHtml
())
builder
.
setStyle
(
bigText
)
}
return
builder
.
build
()
}
}
internal
fun
createSingleNotification
(
context
:
Context
,
lastPushMessage
:
PushMessage
):
Notification
?
{
with
(
lastPushMessage
)
{
if
(
host
==
null
||
message
==
null
||
title
==
null
)
{
return
null
}
val
id
=
notificationId
.
toInt
()
val
contentIntent
=
getContentIntent
(
context
,
id
,
lastPushMessage
)
val
deleteIntent
=
getDismissIntent
(
context
,
lastPushMessage
)
val
builder
=
NotificationCompat
.
Builder
(
context
)
.
setWhen
(
createdAt
)
.
setContentTitle
(
title
.
fromHtml
())
.
setContentText
(
message
.
fromHtml
())
.
setGroupSummary
(
false
)
.
setGroup
(
host
)
.
setDeleteIntent
(
deleteIntent
)
.
setContentIntent
(
contentIntent
)
.
setMessageNotification
()
val
subText
=
RocketChatCache
(
context
).
getHostSiteName
(
host
)
if
(
subText
.
isNotEmpty
())
{
builder
.
setSubText
(
subText
)
}
val
pushMessageList
=
hostToPushMessageList
.
get
(
host
)
pushMessageList
?.
let
{
val
lastPushMsg
=
pushMessageList
.
last
()
if
(
lastPushMsg
.
host
==
null
||
lastPushMsg
.
message
==
null
||
lastPushMsg
.
title
==
null
)
{
return
null
}
if
(
pushMessageList
.
isNotEmpty
())
{
val
messageCount
=
pushMessageList
.
size
val
bigText
=
NotificationCompat
.
BigTextStyle
()
.
bigText
(
lastPushMsg
.
message
.
fromHtml
())
.
setBigContentTitle
(
lastPushMsg
.
title
.
fromHtml
())
builder
.
setStyle
(
bigText
).
setNumber
(
messageCount
)
}
}
return
builder
.
build
()
}
}
@RequiresApi
(
Build
.
VERSION_CODES
.
N
)
internal
fun
createSingleNotificationForNougatAndAbove
(
context
:
Context
,
lastPushMessage
:
PushMessage
):
Notification
?
{
val
manager
:
NotificationManager
=
context
.
getSystemService
(
Context
.
NOTIFICATION_SERVICE
)
as
NotificationManager
with
(
lastPushMessage
)
{
if
(
host
==
null
||
message
==
null
||
title
==
null
)
{
return
null
}
val
id
=
notificationId
.
toInt
()
val
contentIntent
=
getContentIntent
(
context
,
id
,
lastPushMessage
)
val
deleteIntent
=
getDismissIntent
(
context
,
lastPushMessage
)
val
builder
=
Notification
.
Builder
(
context
)
.
setWhen
(
createdAt
)
.
setContentTitle
(
title
.
fromHtml
())
.
setContentText
(
message
.
fromHtml
())
.
setGroup
(
host
)
.
setGroupSummary
(
false
)
.
setDeleteIntent
(
deleteIntent
)
.
setContentIntent
(
contentIntent
)
.
setMessageNotification
(
context
)
.
addReplyAction
(
context
,
lastPushMessage
)
if
(
isAndroidVersionAtLeast
(
android
.
os
.
Build
.
VERSION_CODES
.
O
))
{
builder
.
setChannelId
(
host
)
val
channel
=
NotificationChannel
(
host
,
host
,
NotificationManager
.
IMPORTANCE_HIGH
)
channel
.
lockscreenVisibility
=
Notification
.
VISIBILITY_PUBLIC
channel
.
enableLights
(
false
)
channel
.
enableVibration
(
true
)
channel
.
setShowBadge
(
true
)
manager
.
createNotificationChannel
(
channel
)
}
val
subText
=
RocketChatCache
(
context
).
getHostSiteName
(
host
)
if
(
subText
.
isNotEmpty
())
{
builder
.
setSubText
(
subText
)
}
if
(
style
==
null
||
"inbox"
==
style
)
{
val
pushMessageList
=
hostToPushMessageList
.
get
(
host
)
pushMessageList
?.
let
{
val
userMessages
=
pushMessageList
.
filter
{
it
.
notificationId
==
lastPushMessage
.
notificationId
}
val
count
=
pushMessageList
.
filter
{
it
.
title
==
title
}.
size
builder
.
setContentTitle
(
getTitle
(
count
,
title
))
if
(
count
>
1
)
{
val
inbox
=
Notification
.
InboxStyle
()
inbox
.
setBigContentTitle
(
getTitle
(
count
,
title
))
for
(
push
in
userMessages
)
{
inbox
.
addLine
(
push
.
message
)
}
builder
.
setStyle
(
inbox
)
}
else
{
val
bigTextStyle
=
Notification
.
BigTextStyle
()
.
bigText
(
message
.
fromHtml
())
builder
.
setStyle
(
bigTextStyle
)
}
}
}
else
{
val
bigTextStyle
=
Notification
.
BigTextStyle
()
.
bigText
(
message
.
fromHtml
())
builder
.
setStyle
(
bigTextStyle
)
}
return
builder
.
build
()
}
}
private
fun
getTitle
(
messageCount
:
Int
,
title
:
String
):
CharSequence
{
return
if
(
messageCount
>
1
)
"($messageCount) ${title.fromHtml()}"
else
title
.
fromHtml
()
}
private
fun
getDismissIntent
(
context
:
Context
,
pushMessage
:
PushMessage
):
PendingIntent
{
val
deleteIntent
=
Intent
(
context
,
DeleteReceiver
::
class
.
java
)
.
putExtra
(
EXTRA_NOT_ID
,
pushMessage
.
notificationId
.
toInt
())
.
putExtra
(
EXTRA_HOSTNAME
,
pushMessage
.
host
)
return
PendingIntent
.
getBroadcast
(
context
,
pushMessage
.
notificationId
.
toInt
(),
deleteIntent
,
PendingIntent
.
FLAG_UPDATE_CURRENT
)
}
private
fun
getContentIntent
(
context
:
Context
,
notificationId
:
Int
,
pushMessage
:
PushMessage
,
grouped
:
Boolean
=
false
):
PendingIntent
{
val
notificationIntent
=
Intent
(
context
,
MainActivity
::
class
.
java
)
.
addFlags
(
Intent
.
FLAG_ACTIVITY_SINGLE_TOP
or
Intent
.
FLAG_ACTIVITY_CLEAR_TOP
)
.
putExtra
(
EXTRA_NOT_ID
,
notificationId
)
.
putExtra
(
EXTRA_HOSTNAME
,
pushMessage
.
host
)
if
(!
grouped
)
{
notificationIntent
.
putExtra
(
EXTRA_ROOM_ID
,
pushMessage
.
rid
)
}
return
PendingIntent
.
getActivity
(
context
,
randomizer
.
nextInt
(),
notificationIntent
,
PendingIntent
.
FLAG_UPDATE_CURRENT
)
}
// CharSequence extensions
private
fun
CharSequence
.
fromHtml
():
Spanned
{
return
Html
.
fromHtml
(
this
as
String
)
}
//Notification.Builder extensions
@RequiresApi
(
Build
.
VERSION_CODES
.
N
)
private
fun
Notification
.
Builder
.
addReplyAction
(
ctx
:
Context
,
pushMessage
:
PushMessage
):
Notification
.
Builder
{
val
replyRemoteInput
=
android
.
app
.
RemoteInput
.
Builder
(
REMOTE_INPUT_REPLY
)
.
setLabel
(
REPLY_LABEL
)
.
build
()
val
replyIntent
=
Intent
(
ctx
,
ReplyReceiver
::
class
.
java
)
replyIntent
.
putExtra
(
EXTRA_PUSH_MESSAGE
,
pushMessage
as
Serializable
)
val
pendingIntent
=
PendingIntent
.
getBroadcast
(
ctx
,
randomizer
.
nextInt
(),
replyIntent
,
0
)
val
replyAction
=
Notification
.
Action
.
Builder
(
Icon
.
createWithResource
(
ctx
,
R
.
drawable
.
ic_reply
),
REPLY_LABEL
,
pendingIntent
)
.
addRemoteInput
(
replyRemoteInput
)
.
setAllowGeneratedReplies
(
true
)
.
build
()
this
.
addAction
(
replyAction
)
return
this
}
@RequiresApi
(
Build
.
VERSION_CODES
.
N
)
private
fun
Notification
.
Builder
.
setMessageNotification
(
ctx
:
Context
):
Notification
.
Builder
{
val
res
=
ctx
.
resources
val
smallIcon
=
res
.
getIdentifier
(
"rocket_chat_notification"
,
"drawable"
,
ctx
.
packageName
)
with
(
this
,
{
setAutoCancel
(
true
)
setShowWhen
(
true
)
setColor
(
res
.
getColor
(
R
.
color
.
colorRed400
,
ctx
.
theme
))
setSmallIcon
(
smallIcon
)
})
return
this
}
// NotificationCompat.Builder extensions
private
fun
NotificationCompat
.
Builder
.
addReplyAction
(
pushMessage
:
PushMessage
):
NotificationCompat
.
Builder
{
val
context
=
this
.
mContext
val
replyRemoteInput
=
RemoteInput
.
Builder
(
REMOTE_INPUT_REPLY
)
.
setLabel
(
REPLY_LABEL
)
.
build
()
val
replyIntent
=
Intent
(
context
,
ReplyReceiver
::
class
.
java
)
replyIntent
.
putExtra
(
EXTRA_PUSH_MESSAGE
,
pushMessage
as
Serializable
)
val
pendingIntent
=
PendingIntent
.
getBroadcast
(
context
,
randomizer
.
nextInt
(),
replyIntent
,
0
)
val
replyAction
=
NotificationCompat
.
Action
.
Builder
(
R
.
drawable
.
ic_reply
,
REPLY_LABEL
,
pendingIntent
)
.
addRemoteInput
(
replyRemoteInput
)
.
setAllowGeneratedReplies
(
true
)
.
build
()
this
.
addAction
(
replyAction
)
return
this
}
private
fun
NotificationCompat
.
Builder
.
setMessageNotification
():
NotificationCompat
.
Builder
{
val
ctx
=
this
.
mContext
val
res
=
ctx
.
resources
val
smallIcon
=
res
.
getIdentifier
(
"rocket_chat_notification"
,
"drawable"
,
ctx
.
packageName
)
with
(
this
,
{
setAutoCancel
(
true
)
setShowWhen
(
true
)
color
=
ctx
.
resources
.
getColor
(
R
.
color
.
colorRed400
)
setDefaults
(
Notification
.
DEFAULT_ALL
)
setSmallIcon
(
smallIcon
)
})
return
this
}
internal
data class
PushMessage
(
val
title
:
String
?
=
null
,
val
message
:
String
?
=
null
,
val
image
:
String
?
=
null
,
val
ejson
:
String
?
=
null
,
val
count
:
String
?
=
null
,
val
notificationId
:
String
,
val
summaryText
:
String
?
=
null
,
val
style
:
String
?
=
null
)
:
Serializable
{
val
host
:
String
?
val
rid
:
String
?
val
type
:
String
?
val
channelName
:
String
?
val
sender
:
Sender
?
val
createdAt
:
Long
init
{
val
json
=
if
(
ejson
==
null
)
JSONObject
()
else
JSONObject
(
ejson
)
host
=
json
.
optString
(
"host"
,
null
)
rid
=
json
.
optString
(
"rid"
,
null
)
type
=
json
.
optString
(
"type"
,
null
)
channelName
=
json
.
optString
(
"name"
,
null
)
val
senderJson
=
json
.
optString
(
"sender"
,
null
)
if
(
senderJson
!=
null
&&
senderJson
!=
"null"
)
{
sender
=
Sender
(
senderJson
)
}
else
{
sender
=
null
}
createdAt
=
System
.
currentTimeMillis
()
}
data class
Sender
(
val
sender
:
String
)
:
Serializable
{
val
_id
:
String
?
val
username
:
String
?
val
name
:
String
?
init
{
val
json
=
JSONObject
(
sender
)
_id
=
json
.
optString
(
"_id"
,
null
)
username
=
json
.
optString
(
"username"
,
null
)
name
=
json
.
optString
(
"name"
,
null
)
}
}
}
/**
* BroadcastReceiver for dismissed notifications.
*/
class
DeleteReceiver
:
BroadcastReceiver
()
{
override
fun
onReceive
(
context
:
Context
?,
intent
:
Intent
?)
{
val
notId
=
intent
?.
extras
?.
getInt
(
EXTRA_NOT_ID
)
val
host
=
intent
?.
extras
?.
getString
(
EXTRA_HOSTNAME
)
if
(
host
!=
null
&&
notId
!=
null
)
{
clearNotificationsByHostAndNotificationId
(
host
,
notId
)
}
}
}
/**
* *EXPERIMENTAL*
*
* BroadcastReceiver for notifications' replies using Direct Reply feature (Android >= 7).
*/
class
ReplyReceiver
:
BroadcastReceiver
()
{
override
fun
onReceive
(
context
:
Context
?,
intent
:
Intent
?)
{
if
(
context
==
null
)
{
return
}
synchronized
(
this
)
{
val
manager
=
context
.
getSystemService
(
Context
.
NOTIFICATION_SERVICE
)
as
NotificationManager
val
message
:
CharSequence
?
=
extractMessage
(
intent
)
val
pushMessage
=
intent
?.
extras
?.
getSerializable
(
EXTRA_PUSH_MESSAGE
)
as
PushMessage
?
if
(
pushMessage
?.
host
==
null
)
{
return
}
pushMessage
.
let
{
val
groupTuple
=
groupMap
.
get
(
pushMessage
.
host
)
val
pushes
=
hostToPushMessageList
.
get
(
pushMessage
.
host
)
pushes
?.
let
{
val
allMessagesFromSameUser
=
pushes
.
filter
{
it
.
sender
?.
_id
==
pushMessage
.
sender
?.
_id
}
for
(
msg
in
allMessagesFromSameUser
)
{
manager
.
cancel
(
msg
.
notificationId
.
toInt
())
groupTuple
?.
second
?.
decrementAndGet
()
}
groupTuple
?.
let
{
val
groupNotId
=
groupTuple
.
first
val
totalNot
=
groupTuple
.
second
.
get
()
if
(
totalNot
==
0
)
{
manager
.
cancel
(
groupNotId
)
}
}
message
?.
let
{
if
(
pushMessage
.
rid
==
null
)
{
return
}
val
httpUrl
=
HttpUrl
.
parse
(
pushMessage
.
host
)
httpUrl
?.
let
{
val
siteUrl
=
RocketChatCache
(
context
).
getSiteUrlFor
(
httpUrl
.
host
())
if
(
siteUrl
!=
null
)
{
sendMessage
(
siteUrl
,
message
,
pushMessage
.
rid
)
}
}
}
}
}
}
}
private
fun
extractMessage
(
intent
:
Intent
?):
CharSequence
?
{
val
remoteInput
:
Bundle
?
=
RemoteInput
.
getResultsFromIntent
(
intent
)
return
remoteInput
?.
getCharSequence
(
REMOTE_INPUT_REPLY
)
}
// Just kept for reference. We should use this on rewrite with job schedulers
private
fun
sendMessage
(
hostname
:
String
,
message
:
CharSequence
,
roomId
:
String
)
{
val
roomRepository
=
RealmRoomRepository
(
hostname
)
val
userRepository
=
RealmUserRepository
(
hostname
)
val
messageRepository
=
RealmMessageRepository
(
hostname
)
val
messageInteractor
=
MessageInteractor
(
messageRepository
,
roomRepository
)
val
singleRoom
:
Single
<
Room
>
=
roomRepository
.
getById
(
roomId
)
.
filter
({
it
.
isPresent
})
.
map
({
it
.
get
()
})
.
firstElement
()
.
toSingle
()
val
singleUser
:
Single
<
User
>
=
userRepository
.
getCurrent
()
.
filter
({
it
.
isPresent
})
.
map
({
it
.
get
()
})
.
firstElement
()
.
toSingle
()
val
roomUserTuple
:
Single
<
TupleRoomUser
>
=
Single
.
zip
(
singleRoom
,
singleUser
,
BiFunction
{
room
,
user
->
TupleRoomUser
(
room
,
user
)
})
roomUserTuple
.
flatMap
{
tuple
->
messageInteractor
.
send
(
tuple
.
first
,
tuple
.
second
,
message
as
String
)
}
.
subscribeOn
(
AndroidSchedulers
.
from
(
BackgroundLooper
.
get
()))
.
observeOn
(
AndroidSchedulers
.
mainThread
())
.
subscribe
({
_
->
// Empty
},
{
throwable
->
throwable
.
printStackTrace
()
Logger
.
report
(
throwable
)
})
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/push/PushNotificationHandler.java
deleted
100644 → 0
View file @
1f3713b3
package
chat
.
rocket
.
android
.
push
;
import
android.app.Notification
;
import
android.app.NotificationChannel
;
import
android.app.NotificationManager
;
import
android.app.PendingIntent
;
import
android.content.ContentResolver
;
import
android.content.Context
;
import
android.content.Intent
;
import
android.content.SharedPreferences
;
import
android.content.res.AssetManager
;
import
android.content.res.Resources
;
import
android.graphics.Bitmap
;
import
android.graphics.BitmapFactory
;
import
android.graphics.Color
;
import
android.net.Uri
;
import
android.os.Build
;
import
android.os.Bundle
;
import
android.support.annotation.RequiresApi
;
import
android.support.v4.app.NotificationCompat
;
import
android.support.v4.app.RemoteInput
;
import
android.support.v4.util.SparseArrayCompat
;
import
android.text.Html
;
import
android.text.Spanned
;
import
android.util.Log
;
import
org.json.JSONArray
;
import
org.json.JSONException
;
import
org.json.JSONObject
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.net.HttpURLConnection
;
import
java.net.URL
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.Random
;
import
chat.rocket.android.activity.MainActivity
;
import
chat.rocket.android.helper.ServerPolicyHelper
;
import
chat.rocket.android.service.ConnectivityManager
;
import
chat.rocket.android.widget.helper.AvatarHelper
;
import
chat.rocket.core.models.ServerInfo
;
public
class
PushNotificationHandler
implements
PushConstants
{
private
static
final
String
LOG_TAG
=
"PushNotificationHandler"
;
private
static
SparseArrayCompat
<
ArrayList
<
String
>>
messageMap
=
new
SparseArrayCompat
<>();
private
Random
random
=
new
Random
();
public
static
synchronized
void
cleanUpNotificationStack
(
int
notId
)
{
messageMap
.
remove
(
notId
);
}
private
synchronized
void
setNotification
(
int
notId
,
String
message
)
{
ArrayList
<
String
>
messageList
=
messageMap
.
get
(
notId
);
if
(
messageList
==
null
)
{
messageList
=
new
ArrayList
<>();
messageMap
.
put
(
notId
,
messageList
);
}
if
(
message
.
isEmpty
())
{
messageList
.
clear
();
}
else
{
messageList
.
add
(
message
);
}
}
private
synchronized
ArrayList
<
String
>
getMessageList
(
int
notId
)
{
return
messageMap
.
get
(
notId
);
}
public
void
showNotificationIfPossible
(
Context
context
,
Bundle
extras
)
{
// Send a notification if there is a message or title, otherwise just send data
String
message
=
extras
.
getString
(
MESSAGE
);
String
title
=
extras
.
getString
(
TITLE
);
String
contentAvailable
=
extras
.
getString
(
CONTENT_AVAILABLE
);
String
forceStart
=
extras
.
getString
(
FORCE_START
);
Log
.
d
(
LOG_TAG
,
"message =["
+
message
+
"]"
);
Log
.
d
(
LOG_TAG
,
"title =["
+
title
+
"]"
);
Log
.
d
(
LOG_TAG
,
"contentAvailable =["
+
contentAvailable
+
"]"
);
Log
.
d
(
LOG_TAG
,
"forceStart =["
+
forceStart
+
"]"
);
if
((
message
!=
null
&&
message
.
length
()
!=
0
)
||
(
title
!=
null
&&
title
.
length
()
!=
0
))
{
Log
.
d
(
LOG_TAG
,
"build notification"
);
if
(
title
==
null
||
title
.
isEmpty
())
{
extras
.
putString
(
TITLE
,
getAppName
(
context
));
}
createNotification
(
context
,
extras
);
}
}
public
void
createNotification
(
Context
context
,
Bundle
extras
)
{
NotificationManager
notificationManager
=
(
NotificationManager
)
context
.
getSystemService
(
Context
.
NOTIFICATION_SERVICE
);
String
appName
=
getAppName
(
context
);
String
packageName
=
context
.
getPackageName
();
Resources
resources
=
context
.
getResources
();
String
hostname
=
getHostname
(
extras
);
String
roomId
=
getRoomId
(
extras
);
int
notId
=
parseInt
(
NOT_ID
,
extras
);
Intent
notificationIntent
=
new
Intent
(
context
,
MainActivity
.
class
);
notificationIntent
.
addFlags
(
Intent
.
FLAG_ACTIVITY_SINGLE_TOP
|
Intent
.
FLAG_ACTIVITY_CLEAR_TOP
);
notificationIntent
.
putExtra
(
PUSH_BUNDLE
,
extras
);
notificationIntent
.
putExtra
(
NOT_ID
,
notId
);
if
(
hostname
!=
null
&&
roomId
!=
null
&&
isValidHostname
(
context
,
hostname
))
{
notificationIntent
.
putExtra
(
HOSTNAME
,
hostname
);
notificationIntent
.
putExtra
(
ROOM_ID
,
roomId
);
}
int
requestCode
=
random
.
nextInt
();
PendingIntent
contentIntent
=
PendingIntent
.
getActivity
(
context
,
requestCode
,
notificationIntent
,
PendingIntent
.
FLAG_UPDATE_CURRENT
);
SharedPreferences
prefs
=
context
.
getSharedPreferences
(
PushConstants
.
COM_ADOBE_PHONEGAP_PUSH
,
Context
.
MODE_PRIVATE
);
String
localIcon
=
prefs
.
getString
(
ICON
,
null
);
String
localIconColor
=
prefs
.
getString
(
ICON_COLOR
,
null
);
boolean
soundOption
=
prefs
.
getBoolean
(
SOUND
,
true
);
boolean
vibrateOption
=
prefs
.
getBoolean
(
VIBRATE
,
true
);
Log
.
d
(
LOG_TAG
,
"stored icon="
+
localIcon
);
Log
.
d
(
LOG_TAG
,
"stored iconColor="
+
localIconColor
);
Log
.
d
(
LOG_TAG
,
"stored sound="
+
soundOption
);
Log
.
d
(
LOG_TAG
,
"stored vibrate="
+
vibrateOption
);
if
(
Build
.
VERSION
.
SDK_INT
>=
26
)
{
String
channelId
=
"rocket-chat-channel"
;
CharSequence
name
=
"RocketChatMessage"
;
int
importance
=
NotificationManager
.
IMPORTANCE_HIGH
;
NotificationChannel
channel
=
new
NotificationChannel
(
channelId
,
name
,
importance
);
channel
.
enableLights
(
true
);
notificationManager
.
createNotificationChannel
(
channel
);
Notification
.
Builder
notificationBuilder
=
new
Notification
.
Builder
(
context
,
channelId
)
.
setWhen
(
System
.
currentTimeMillis
())
.
setContentTitle
(
fromHtml
(
extras
.
getString
(
TITLE
)))
.
setTicker
(
fromHtml
(
extras
.
getString
(
TITLE
)))
.
setContentIntent
(
contentIntent
)
.
setChannelId
(
channelId
)
.
setAutoCancel
(
true
);
setNotificationImportance
(
extras
,
channel
);
setNotificationVibration
(
extras
,
vibrateOption
,
channel
);
setNotificationMessage
(
notId
,
extras
,
notificationBuilder
);
setNotificationCount
(
context
,
extras
,
notificationBuilder
);
setNotificationSmallIcon
(
extras
,
packageName
,
resources
,
notificationBuilder
,
localIcon
);
setNotificationLargeIcon
(
context
,
extras
,
packageName
,
resources
,
notificationBuilder
);
setNotificationLedColor
(
extras
,
channel
);
if
(
soundOption
)
{
setNotificationSound
(
context
,
extras
,
channel
);
}
createActions
(
context
,
extras
,
notificationBuilder
,
resources
,
packageName
,
notId
);
notificationManager
.
notify
(
notId
,
notificationBuilder
.
build
());
}
else
{
NotificationCompat
.
Builder
notificationBuilder
=
new
NotificationCompat
.
Builder
(
context
)
.
setWhen
(
System
.
currentTimeMillis
())
.
setContentTitle
(
fromHtml
(
extras
.
getString
(
TITLE
)))
.
setTicker
(
fromHtml
(
extras
.
getString
(
TITLE
)))
.
setContentIntent
(
contentIntent
)
.
setAutoCancel
(
true
);
setNotificationCount
(
context
,
extras
,
notificationBuilder
);
setNotificationVibration
(
extras
,
vibrateOption
,
notificationBuilder
);
setNotificationIconColor
(
extras
.
getString
(
"color"
),
notificationBuilder
,
localIconColor
);
setNotificationSmallIcon
(
extras
,
packageName
,
resources
,
notificationBuilder
,
localIcon
);
setNotificationLargeIcon
(
context
,
extras
,
packageName
,
resources
,
notificationBuilder
);
if
(
soundOption
)
{
setNotificationSound
(
context
,
extras
,
notificationBuilder
);
}
setNotificationLedColor
(
extras
,
notificationBuilder
);
setNotificationPriority
(
extras
,
notificationBuilder
);
setNotificationMessage
(
notId
,
extras
,
notificationBuilder
);
setVisibility
(
context
,
extras
,
notificationBuilder
);
createActions
(
context
,
extras
,
notificationBuilder
,
resources
,
packageName
,
notId
);
notificationManager
.
notify
(
appName
,
notId
,
notificationBuilder
.
build
());
}
}
private
void
createActions
(
Context
context
,
Bundle
extras
,
NotificationCompat
.
Builder
builder
,
Resources
resources
,
String
packageName
,
int
notId
)
{
Log
.
d
(
LOG_TAG
,
"build actions: with in-line"
);
String
actions
=
extras
.
getString
(
ACTIONS
);
if
(
actions
==
null
)
{
return
;
}
try
{
JSONArray
actionsArray
=
new
JSONArray
(
actions
);
ArrayList
<
NotificationCompat
.
Action
>
wActions
=
new
ArrayList
<>();
for
(
int
i
=
0
;
i
<
actionsArray
.
length
();
i
++)
{
int
min
=
1
;
int
max
=
2000000000
;
Random
random
=
new
Random
();
int
uniquePendingIntentRequestCode
=
random
.
nextInt
((
max
-
min
)
+
1
)
+
min
;
Log
.
d
(
LOG_TAG
,
"adding action"
);
JSONObject
action
=
actionsArray
.
getJSONObject
(
i
);
Log
.
d
(
LOG_TAG
,
"adding callback = "
+
action
.
getString
(
CALLBACK
));
boolean
foreground
=
action
.
optBoolean
(
FOREGROUND
,
true
);
boolean
inline
=
action
.
optBoolean
(
"inline"
,
false
);
Intent
intent
;
PendingIntent
pIntent
;
if
(
inline
)
{
Log
.
d
(
LOG_TAG
,
"Version: "
+
android
.
os
.
Build
.
VERSION
.
SDK_INT
+
" = "
+
android
.
os
.
Build
.
VERSION_CODES
.
M
);
if
(
android
.
os
.
Build
.
VERSION
.
SDK_INT
<=
android
.
os
.
Build
.
VERSION_CODES
.
M
)
{
Log
.
d
(
LOG_TAG
,
"push activity"
);
intent
=
new
Intent
(
context
,
MainActivity
.
class
);
}
else
{
Log
.
d
(
LOG_TAG
,
"push receiver"
);
intent
=
new
Intent
(
context
,
BackgroundActionButtonHandler
.
class
);
}
updateIntent
(
intent
,
action
.
getString
(
CALLBACK
),
extras
,
foreground
,
notId
);
if
(
android
.
os
.
Build
.
VERSION
.
SDK_INT
<=
android
.
os
.
Build
.
VERSION_CODES
.
M
)
{
Log
.
d
(
LOG_TAG
,
"push activity for notId "
+
notId
);
pIntent
=
PendingIntent
.
getActivity
(
context
,
uniquePendingIntentRequestCode
,
intent
,
PendingIntent
.
FLAG_ONE_SHOT
);
}
else
{
Log
.
d
(
LOG_TAG
,
"push receiver for notId "
+
notId
);
pIntent
=
PendingIntent
.
getBroadcast
(
context
,
uniquePendingIntentRequestCode
,
intent
,
PendingIntent
.
FLAG_ONE_SHOT
);
}
}
else
if
(
foreground
)
{
intent
=
new
Intent
(
context
,
MainActivity
.
class
);
updateIntent
(
intent
,
action
.
getString
(
CALLBACK
),
extras
,
foreground
,
notId
);
pIntent
=
PendingIntent
.
getActivity
(
context
,
uniquePendingIntentRequestCode
,
intent
,
PendingIntent
.
FLAG_UPDATE_CURRENT
);
}
else
{
intent
=
new
Intent
(
context
,
BackgroundActionButtonHandler
.
class
);
updateIntent
(
intent
,
action
.
getString
(
CALLBACK
),
extras
,
foreground
,
notId
);
pIntent
=
PendingIntent
.
getBroadcast
(
context
,
uniquePendingIntentRequestCode
,
intent
,
PendingIntent
.
FLAG_UPDATE_CURRENT
);
}
NotificationCompat
.
Action
.
Builder
actionBuilder
=
new
NotificationCompat
.
Action
.
Builder
(
resources
.
getIdentifier
(
action
.
optString
(
ICON
,
""
),
DRAWABLE
,
packageName
),
action
.
getString
(
TITLE
),
pIntent
);
RemoteInput
remoteInput
;
if
(
inline
)
{
Log
.
d
(
LOG_TAG
,
"build remote input"
);
String
replyLabel
=
"Enter your reply here"
;
remoteInput
=
new
RemoteInput
.
Builder
(
INLINE_REPLY
)
.
setLabel
(
replyLabel
)
.
build
();
actionBuilder
.
addRemoteInput
(
remoteInput
);
}
NotificationCompat
.
Action
wAction
=
actionBuilder
.
build
();
wActions
.
add
(
actionBuilder
.
build
());
if
(
inline
)
{
builder
.
addAction
(
wAction
);
}
else
{
builder
.
addAction
(
resources
.
getIdentifier
(
action
.
optString
(
ICON
,
""
),
DRAWABLE
,
packageName
),
action
.
getString
(
TITLE
),
pIntent
);
}
wAction
=
null
;
pIntent
=
null
;
}
builder
.
extend
(
new
NotificationCompat
.
WearableExtender
().
addActions
(
wActions
));
wActions
.
clear
();
}
catch
(
JSONException
e
)
{
// nope
}
}
@RequiresApi
(
api
=
Build
.
VERSION_CODES
.
KITKAT_WATCH
)
private
void
createActions
(
Context
context
,
Bundle
extras
,
Notification
.
Builder
builder
,
Resources
resources
,
String
packageName
,
int
notId
)
{
Log
.
d
(
LOG_TAG
,
"build actions: with in-line"
);
String
actions
=
extras
.
getString
(
ACTIONS
);
if
(
actions
==
null
)
{
return
;
}
try
{
JSONArray
actionsArray
=
new
JSONArray
(
actions
);
ArrayList
<
Notification
.
Action
>
wActions
=
new
ArrayList
<>();
for
(
int
i
=
0
;
i
<
actionsArray
.
length
();
i
++)
{
int
min
=
1
;
int
max
=
2000000000
;
Random
random
=
new
Random
();
int
uniquePendingIntentRequestCode
=
random
.
nextInt
((
max
-
min
)
+
1
)
+
min
;
Log
.
d
(
LOG_TAG
,
"adding action"
);
JSONObject
action
=
actionsArray
.
getJSONObject
(
i
);
Log
.
d
(
LOG_TAG
,
"adding callback = "
+
action
.
getString
(
CALLBACK
));
boolean
foreground
=
action
.
optBoolean
(
FOREGROUND
,
true
);
boolean
inline
=
action
.
optBoolean
(
"inline"
,
false
);
Intent
intent
;
PendingIntent
pIntent
;
if
(
inline
)
{
Log
.
d
(
LOG_TAG
,
"Version: "
+
android
.
os
.
Build
.
VERSION
.
SDK_INT
+
" = "
+
android
.
os
.
Build
.
VERSION_CODES
.
M
);
if
(
android
.
os
.
Build
.
VERSION
.
SDK_INT
<=
android
.
os
.
Build
.
VERSION_CODES
.
M
)
{
Log
.
d
(
LOG_TAG
,
"push activity"
);
intent
=
new
Intent
(
context
,
MainActivity
.
class
);
}
else
{
Log
.
d
(
LOG_TAG
,
"push receiver"
);
intent
=
new
Intent
(
context
,
BackgroundActionButtonHandler
.
class
);
}
updateIntent
(
intent
,
action
.
getString
(
CALLBACK
),
extras
,
foreground
,
notId
);
if
(
android
.
os
.
Build
.
VERSION
.
SDK_INT
<=
android
.
os
.
Build
.
VERSION_CODES
.
M
)
{
Log
.
d
(
LOG_TAG
,
"push activity for notId "
+
notId
);
pIntent
=
PendingIntent
.
getActivity
(
context
,
uniquePendingIntentRequestCode
,
intent
,
PendingIntent
.
FLAG_ONE_SHOT
);
}
else
{
Log
.
d
(
LOG_TAG
,
"push receiver for notId "
+
notId
);
pIntent
=
PendingIntent
.
getBroadcast
(
context
,
uniquePendingIntentRequestCode
,
intent
,
PendingIntent
.
FLAG_ONE_SHOT
);
}
}
else
if
(
foreground
)
{
intent
=
new
Intent
(
context
,
MainActivity
.
class
);
updateIntent
(
intent
,
action
.
getString
(
CALLBACK
),
extras
,
foreground
,
notId
);
pIntent
=
PendingIntent
.
getActivity
(
context
,
uniquePendingIntentRequestCode
,
intent
,
PendingIntent
.
FLAG_UPDATE_CURRENT
);
}
else
{
intent
=
new
Intent
(
context
,
BackgroundActionButtonHandler
.
class
);
updateIntent
(
intent
,
action
.
getString
(
CALLBACK
),
extras
,
foreground
,
notId
);
pIntent
=
PendingIntent
.
getBroadcast
(
context
,
uniquePendingIntentRequestCode
,
intent
,
PendingIntent
.
FLAG_UPDATE_CURRENT
);
}
Notification
.
Action
.
Builder
actionBuilder
=
new
Notification
.
Action
.
Builder
(
resources
.
getIdentifier
(
action
.
optString
(
ICON
,
""
),
DRAWABLE
,
packageName
),
action
.
getString
(
TITLE
),
pIntent
);
android
.
app
.
RemoteInput
remoteInput
;
if
(
inline
)
{
Log
.
d
(
LOG_TAG
,
"build remote input"
);
String
replyLabel
=
"Enter your reply here"
;
remoteInput
=
new
android
.
app
.
RemoteInput
.
Builder
(
INLINE_REPLY
)
.
setLabel
(
replyLabel
)
.
build
();
actionBuilder
.
addRemoteInput
(
remoteInput
);
}
Notification
.
Action
wAction
=
actionBuilder
.
build
();
wActions
.
add
(
actionBuilder
.
build
());
if
(
inline
)
{
builder
.
addAction
(
wAction
);
}
else
{
builder
.
addAction
(
resources
.
getIdentifier
(
action
.
optString
(
ICON
,
""
),
DRAWABLE
,
packageName
),
action
.
getString
(
TITLE
),
pIntent
);
}
wAction
=
null
;
pIntent
=
null
;
}
builder
.
extend
(
new
Notification
.
WearableExtender
().
addActions
(
wActions
));
wActions
.
clear
();
}
catch
(
JSONException
e
)
{
// nope
}
}
private
void
setNotificationCount
(
Context
context
,
Bundle
extras
,
NotificationCompat
.
Builder
builder
)
{
int
count
=
extractBadgeCount
(
extras
);
if
(
count
>=
0
)
{
Log
.
d
(
LOG_TAG
,
"count =["
+
count
+
"]"
);
builder
.
setNumber
(
count
);
}
}
private
void
setNotificationCount
(
Context
context
,
Bundle
extras
,
Notification
.
Builder
builder
)
{
int
count
=
extractBadgeCount
(
extras
);
if
(
count
>=
0
)
{
Log
.
d
(
LOG_TAG
,
"count =["
+
count
+
"]"
);
builder
.
setNumber
(
count
);
}
}
private
void
setVisibility
(
Context
context
,
Bundle
extras
,
NotificationCompat
.
Builder
builder
)
{
String
visibilityStr
=
extras
.
getString
(
VISIBILITY
);
if
(
visibilityStr
==
null
)
{
return
;
}
try
{
Integer
visibility
=
Integer
.
parseInt
(
visibilityStr
);
if
(
visibility
>=
NotificationCompat
.
VISIBILITY_SECRET
&&
visibility
<=
NotificationCompat
.
VISIBILITY_PUBLIC
)
{
builder
.
setVisibility
(
visibility
);
}
else
{
Log
.
e
(
LOG_TAG
,
"Visibility parameter must be between -1 and 1"
);
}
}
catch
(
NumberFormatException
e
)
{
e
.
printStackTrace
();
}
}
private
void
setNotificationVibration
(
Bundle
extras
,
Boolean
vibrateOption
,
NotificationCompat
.
Builder
builder
)
{
String
vibrationPattern
=
extras
.
getString
(
VIBRATION_PATTERN
);
if
(
vibrationPattern
!=
null
)
{
String
[]
items
=
vibrationPattern
.
replaceAll
(
"\\["
,
""
).
replaceAll
(
"\\]"
,
""
).
split
(
","
);
long
[]
results
=
new
long
[
items
.
length
];
for
(
int
i
=
0
;
i
<
items
.
length
;
i
++)
{
try
{
results
[
i
]
=
Long
.
parseLong
(
items
[
i
].
trim
());
}
catch
(
NumberFormatException
nfe
)
{
}
}
builder
.
setVibrate
(
results
);
}
else
{
if
(
vibrateOption
)
{
builder
.
setDefaults
(
Notification
.
DEFAULT_VIBRATE
);
}
}
}
@RequiresApi
(
api
=
26
)
private
void
setNotificationVibration
(
Bundle
extras
,
Boolean
vibrateOption
,
NotificationChannel
channel
)
{
String
vibrationPattern
=
extras
.
getString
(
VIBRATION_PATTERN
);
if
(
vibrationPattern
!=
null
)
{
String
[]
items
=
vibrationPattern
.
replaceAll
(
"\\["
,
""
).
replaceAll
(
"\\]"
,
""
).
split
(
","
);
long
[]
results
=
new
long
[
items
.
length
];
for
(
int
i
=
0
;
i
<
items
.
length
;
i
++)
{
try
{
results
[
i
]
=
Long
.
parseLong
(
items
[
i
].
trim
());
}
catch
(
NumberFormatException
nfe
)
{
}
}
channel
.
setVibrationPattern
(
results
);
}
else
{
if
(
vibrateOption
)
{
channel
.
enableVibration
(
true
);
}
}
}
private
void
setNotificationMessage
(
int
notId
,
Bundle
extras
,
NotificationCompat
.
Builder
builder
)
{
String
message
=
extras
.
getString
(
MESSAGE
);
String
style
=
extras
.
getString
(
STYLE
,
STYLE_TEXT
);
if
(
STYLE_INBOX
.
equals
(
style
))
{
setNotification
(
notId
,
message
);
builder
.
setContentText
(
fromHtml
(
message
));
ArrayList
<
String
>
messageList
=
getMessageList
(
notId
);
Integer
sizeList
=
messageList
.
size
();
if
(
sizeList
>
1
)
{
String
sizeListMessage
=
sizeList
.
toString
();
String
stacking
=
sizeList
+
" more"
;
if
(
extras
.
getString
(
SUMMARY_TEXT
)
!=
null
)
{
stacking
=
extras
.
getString
(
SUMMARY_TEXT
);
stacking
=
stacking
.
replace
(
"%n%"
,
sizeListMessage
);
}
NotificationCompat
.
InboxStyle
notificationInbox
=
new
NotificationCompat
.
InboxStyle
()
.
setBigContentTitle
(
fromHtml
(
extras
.
getString
(
TITLE
)))
.
setSummaryText
(
fromHtml
(
stacking
));
for
(
int
i
=
messageList
.
size
()
-
1
;
i
>=
0
;
i
--)
{
notificationInbox
.
addLine
(
fromHtml
(
messageList
.
get
(
i
)));
}
builder
.
setStyle
(
notificationInbox
);
}
else
{
NotificationCompat
.
BigTextStyle
bigText
=
new
NotificationCompat
.
BigTextStyle
();
if
(
message
!=
null
)
{
bigText
.
bigText
(
fromHtml
(
message
));
bigText
.
setBigContentTitle
(
fromHtml
(
extras
.
getString
(
TITLE
)));
builder
.
setStyle
(
bigText
);
}
}
}
else
if
(
STYLE_PICTURE
.
equals
(
style
))
{
setNotification
(
notId
,
""
);
NotificationCompat
.
BigPictureStyle
bigPicture
=
new
NotificationCompat
.
BigPictureStyle
();
bigPicture
.
bigPicture
(
getBitmapFromURL
(
extras
.
getString
(
PICTURE
),
null
,
null
));
bigPicture
.
setBigContentTitle
(
fromHtml
(
extras
.
getString
(
TITLE
)));
bigPicture
.
setSummaryText
(
fromHtml
(
extras
.
getString
(
SUMMARY_TEXT
)));
builder
.
setContentTitle
(
fromHtml
(
extras
.
getString
(
TITLE
)));
builder
.
setContentText
(
fromHtml
(
message
));
builder
.
setStyle
(
bigPicture
);
}
else
{
setNotification
(
notId
,
""
);
NotificationCompat
.
BigTextStyle
bigText
=
new
NotificationCompat
.
BigTextStyle
();
if
(
message
!=
null
)
{
builder
.
setContentText
(
fromHtml
(
message
));
bigText
.
bigText
(
fromHtml
(
message
));
bigText
.
setBigContentTitle
(
fromHtml
(
extras
.
getString
(
TITLE
)));
String
summaryText
=
extras
.
getString
(
SUMMARY_TEXT
);
if
(
summaryText
!=
null
)
{
bigText
.
setSummaryText
(
fromHtml
(
summaryText
));
}
builder
.
setStyle
(
bigText
);
}
}
}
private
void
setNotificationMessage
(
int
notId
,
Bundle
extras
,
Notification
.
Builder
builder
)
{
String
message
=
extras
.
getString
(
MESSAGE
);
String
style
=
extras
.
getString
(
STYLE
,
STYLE_TEXT
);
if
(
STYLE_INBOX
.
equals
(
style
))
{
setNotification
(
notId
,
message
);
builder
.
setContentText
(
fromHtml
(
message
));
ArrayList
<
String
>
messageList
=
getMessageList
(
notId
);
Integer
sizeList
=
messageList
.
size
();
if
(
sizeList
>
1
)
{
String
sizeListMessage
=
sizeList
.
toString
();
String
stacking
=
sizeList
+
" more"
;
if
(
extras
.
getString
(
SUMMARY_TEXT
)
!=
null
)
{
stacking
=
extras
.
getString
(
SUMMARY_TEXT
);
stacking
=
stacking
.
replace
(
"%n%"
,
sizeListMessage
);
}
Notification
.
InboxStyle
notificationInbox
=
new
Notification
.
InboxStyle
()
.
setBigContentTitle
(
fromHtml
(
extras
.
getString
(
TITLE
)))
.
setSummaryText
(
fromHtml
(
stacking
));
for
(
int
i
=
messageList
.
size
()
-
1
;
i
>=
0
;
i
--)
{
notificationInbox
.
addLine
(
fromHtml
(
messageList
.
get
(
i
)));
}
builder
.
setStyle
(
notificationInbox
);
}
else
{
Notification
.
BigTextStyle
bigText
=
new
Notification
.
BigTextStyle
();
if
(
message
!=
null
)
{
bigText
.
bigText
(
fromHtml
(
message
));
bigText
.
setBigContentTitle
(
fromHtml
(
extras
.
getString
(
TITLE
)));
builder
.
setStyle
(
bigText
);
}
}
}
else
if
(
STYLE_PICTURE
.
equals
(
style
))
{
setNotification
(
notId
,
""
);
Notification
.
BigPictureStyle
bigPicture
=
new
Notification
.
BigPictureStyle
();
bigPicture
.
bigPicture
(
getBitmapFromURL
(
extras
.
getString
(
PICTURE
),
null
,
null
));
bigPicture
.
setBigContentTitle
(
fromHtml
(
extras
.
getString
(
TITLE
)));
bigPicture
.
setSummaryText
(
fromHtml
(
extras
.
getString
(
SUMMARY_TEXT
)));
builder
.
setContentTitle
(
fromHtml
(
extras
.
getString
(
TITLE
)));
builder
.
setContentText
(
fromHtml
(
message
));
builder
.
setStyle
(
bigPicture
);
}
else
{
setNotification
(
notId
,
""
);
Notification
.
BigTextStyle
bigText
=
new
Notification
.
BigTextStyle
();
if
(
message
!=
null
)
{
builder
.
setContentText
(
fromHtml
(
message
));
bigText
.
bigText
(
fromHtml
(
message
));
bigText
.
setBigContentTitle
(
fromHtml
(
extras
.
getString
(
TITLE
)));
String
summaryText
=
extras
.
getString
(
SUMMARY_TEXT
);
if
(
summaryText
!=
null
)
{
bigText
.
setSummaryText
(
fromHtml
(
summaryText
));
}
builder
.
setStyle
(
bigText
);
}
}
}
private
void
setNotificationSound
(
Context
context
,
Bundle
extras
,
NotificationCompat
.
Builder
builder
)
{
String
soundname
=
extras
.
getString
(
SOUNDNAME
);
if
(
soundname
==
null
)
{
soundname
=
extras
.
getString
(
SOUND
);
}
if
(
SOUND_RINGTONE
.
equals
(
soundname
))
{
builder
.
setSound
(
android
.
provider
.
Settings
.
System
.
DEFAULT_RINGTONE_URI
);
}
else
if
(
soundname
!=
null
&&
!
soundname
.
contentEquals
(
SOUND_DEFAULT
))
{
Uri
sound
=
Uri
.
parse
(
ContentResolver
.
SCHEME_ANDROID_RESOURCE
+
"://"
+
context
.
getPackageName
()
+
"/raw/"
+
soundname
);
Log
.
d
(
LOG_TAG
,
sound
.
toString
());
builder
.
setSound
(
sound
);
}
else
{
builder
.
setSound
(
android
.
provider
.
Settings
.
System
.
DEFAULT_NOTIFICATION_URI
);
}
}
@RequiresApi
(
api
=
26
)
private
void
setNotificationSound
(
Context
context
,
Bundle
extras
,
NotificationChannel
channel
)
{
String
soundname
=
extras
.
getString
(
SOUNDNAME
);
if
(
soundname
==
null
)
{
soundname
=
extras
.
getString
(
SOUND
);
}
if
(
SOUND_RINGTONE
.
equals
(
soundname
))
{
channel
.
setSound
(
android
.
provider
.
Settings
.
System
.
DEFAULT_RINGTONE_URI
,
Notification
.
AUDIO_ATTRIBUTES_DEFAULT
);
}
else
if
(
soundname
!=
null
&&
!
soundname
.
contentEquals
(
SOUND_DEFAULT
))
{
Uri
sound
=
Uri
.
parse
(
ContentResolver
.
SCHEME_ANDROID_RESOURCE
+
"://"
+
context
.
getPackageName
()
+
"/raw/"
+
soundname
);
Log
.
d
(
LOG_TAG
,
sound
.
toString
());
channel
.
setSound
(
sound
,
Notification
.
AUDIO_ATTRIBUTES_DEFAULT
);
}
else
{
channel
.
setSound
(
android
.
provider
.
Settings
.
System
.
DEFAULT_NOTIFICATION_URI
,
Notification
.
AUDIO_ATTRIBUTES_DEFAULT
);
}
}
private
void
setNotificationLedColor
(
Bundle
extras
,
NotificationCompat
.
Builder
builder
)
{
String
ledColor
=
extras
.
getString
(
LED_COLOR
);
if
(
ledColor
==
null
)
{
return
;
}
// Converts parse Int Array from ledColor
String
[]
items
=
ledColor
.
replaceAll
(
"\\["
,
""
).
replaceAll
(
"\\]"
,
""
).
split
(
","
);
int
[]
results
=
new
int
[
items
.
length
];
for
(
int
i
=
0
;
i
<
items
.
length
;
i
++)
{
try
{
results
[
i
]
=
Integer
.
parseInt
(
items
[
i
].
trim
());
}
catch
(
NumberFormatException
nfe
)
{
}
}
if
(
results
.
length
==
4
)
{
builder
.
setLights
(
Color
.
argb
(
results
[
0
],
results
[
1
],
results
[
2
],
results
[
3
]),
500
,
500
);
}
else
{
Log
.
e
(
LOG_TAG
,
"ledColor parameter must be an array of length == 4 (ARGB)"
);
}
}
@RequiresApi
(
api
=
26
)
private
void
setNotificationLedColor
(
Bundle
extras
,
NotificationChannel
channel
)
{
String
ledColor
=
extras
.
getString
(
LED_COLOR
);
if
(
ledColor
==
null
)
{
return
;
}
// Converts parse Int Array from ledColor
String
[]
items
=
ledColor
.
replaceAll
(
"\\["
,
""
).
replaceAll
(
"\\]"
,
""
).
split
(
","
);
int
[]
results
=
new
int
[
items
.
length
];
for
(
int
i
=
0
;
i
<
items
.
length
;
i
++)
{
try
{
results
[
i
]
=
Integer
.
parseInt
(
items
[
i
].
trim
());
}
catch
(
NumberFormatException
nfe
)
{
}
}
if
(
results
.
length
==
4
)
{
channel
.
setLightColor
(
Color
.
argb
(
results
[
0
],
results
[
1
],
results
[
2
],
results
[
3
]));
}
else
{
Log
.
e
(
LOG_TAG
,
"ledColor parameter must be an array of length == 4 (ARGB)"
);
}
}
private
void
setNotificationPriority
(
Bundle
extras
,
NotificationCompat
.
Builder
builder
)
{
String
priorityStr
=
extras
.
getString
(
PRIORITY
);
if
(
priorityStr
==
null
)
{
return
;
}
try
{
Integer
priority
=
Integer
.
parseInt
(
priorityStr
);
if
(
priority
>=
NotificationCompat
.
PRIORITY_MIN
&&
priority
<=
NotificationCompat
.
PRIORITY_MAX
)
{
builder
.
setPriority
(
priority
);
}
else
{
Log
.
e
(
LOG_TAG
,
"Priority parameter must be between -2 and 2"
);
}
}
catch
(
NumberFormatException
e
)
{
e
.
printStackTrace
();
}
}
@RequiresApi
(
api
=
26
)
private
void
setNotificationImportance
(
Bundle
extras
,
NotificationChannel
channel
)
{
String
priorityStr
=
extras
.
getString
(
PRIORITY
);
if
(
priorityStr
==
null
)
{
return
;
}
try
{
Integer
priority
=
Integer
.
parseInt
(
priorityStr
);
if
(
priority
>=
NotificationCompat
.
PRIORITY_MIN
&&
priority
<=
NotificationCompat
.
PRIORITY_MAX
)
{
channel
.
setImportance
(
priority
);
}
else
{
Log
.
e
(
LOG_TAG
,
"Priority parameter must be between -2 and 2"
);
}
}
catch
(
NumberFormatException
e
)
{
e
.
printStackTrace
();
}
}
private
void
setNotificationLargeIcon
(
Context
context
,
Bundle
extras
,
String
packageName
,
Resources
resources
,
NotificationCompat
.
Builder
builder
)
{
String
hostname
=
getHostname
(
extras
);
String
username
=
getSenderUsername
(
extras
);
String
gcmLargeIcon
;
if
(
username
!=
null
&&
!
username
.
isEmpty
())
{
gcmLargeIcon
=
"https://"
+
hostname
+
"/avatar/"
+
username
;
}
else
{
gcmLargeIcon
=
extras
.
getString
(
IMAGE
);
// from gcm
}
if
(
gcmLargeIcon
==
null
||
""
.
equals
(
gcmLargeIcon
))
{
return
;
}
if
(
gcmLargeIcon
.
startsWith
(
"http://"
)
||
gcmLargeIcon
.
startsWith
(
"https://"
))
{
builder
.
setLargeIcon
(
getBitmapFromURL
(
gcmLargeIcon
,
username
,
context
));
Log
.
d
(
LOG_TAG
,
"using remote large-icon from gcm"
);
}
else
{
AssetManager
assetManager
=
context
.
getAssets
();
InputStream
istr
;
try
{
istr
=
assetManager
.
open
(
gcmLargeIcon
);
Bitmap
bitmap
=
BitmapFactory
.
decodeStream
(
istr
);
builder
.
setLargeIcon
(
bitmap
);
Log
.
d
(
LOG_TAG
,
"using assets large-icon from gcm"
);
}
catch
(
IOException
e
)
{
int
largeIconId
=
resources
.
getIdentifier
(
gcmLargeIcon
,
DRAWABLE
,
packageName
);
if
(
largeIconId
!=
0
)
{
Bitmap
largeIconBitmap
=
BitmapFactory
.
decodeResource
(
resources
,
largeIconId
);
builder
.
setLargeIcon
(
largeIconBitmap
);
Log
.
d
(
LOG_TAG
,
"using resources large-icon from gcm"
);
}
else
{
Log
.
d
(
LOG_TAG
,
"Not setting large icon"
);
}
}
}
}
private
void
setNotificationLargeIcon
(
Context
context
,
Bundle
extras
,
String
packageName
,
Resources
resources
,
Notification
.
Builder
builder
)
{
String
hostname
=
getHostname
(
extras
);
String
username
=
getSenderUsername
(
extras
);
String
gcmLargeIcon
;
if
(
username
!=
null
&&
!
username
.
isEmpty
())
{
gcmLargeIcon
=
"https://"
+
hostname
+
"/avatar/"
+
username
;
}
else
{
gcmLargeIcon
=
extras
.
getString
(
IMAGE
);
// from gcm
}
if
(
gcmLargeIcon
==
null
||
""
.
equals
(
gcmLargeIcon
))
{
return
;
}
if
(
gcmLargeIcon
.
startsWith
(
"http://"
)
||
gcmLargeIcon
.
startsWith
(
"https://"
))
{
builder
.
setLargeIcon
(
getBitmapFromURL
(
gcmLargeIcon
,
username
,
context
));
Log
.
d
(
LOG_TAG
,
"using remote large-icon from gcm"
);
}
else
{
AssetManager
assetManager
=
context
.
getAssets
();
InputStream
istr
;
try
{
istr
=
assetManager
.
open
(
gcmLargeIcon
);
Bitmap
bitmap
=
BitmapFactory
.
decodeStream
(
istr
);
builder
.
setLargeIcon
(
bitmap
);
Log
.
d
(
LOG_TAG
,
"using assets large-icon from gcm"
);
}
catch
(
IOException
e
)
{
int
largeIconId
=
resources
.
getIdentifier
(
gcmLargeIcon
,
DRAWABLE
,
packageName
);
if
(
largeIconId
!=
0
)
{
Bitmap
largeIconBitmap
=
BitmapFactory
.
decodeResource
(
resources
,
largeIconId
);
builder
.
setLargeIcon
(
largeIconBitmap
);
Log
.
d
(
LOG_TAG
,
"using resources large-icon from gcm"
);
}
else
{
Log
.
d
(
LOG_TAG
,
"Not setting large icon"
);
}
}
}
}
private
void
setNotificationSmallIcon
(
Bundle
extras
,
String
packageName
,
Resources
resources
,
NotificationCompat
.
Builder
builder
,
String
localIcon
)
{
int
iconId
=
0
;
String
icon
=
extras
.
getString
(
ICON
);
if
(
icon
!=
null
&&
!
""
.
equals
(
icon
))
{
iconId
=
resources
.
getIdentifier
(
icon
,
DRAWABLE
,
packageName
);
Log
.
d
(
LOG_TAG
,
"using icon from plugin options"
);
}
else
if
(
localIcon
!=
null
&&
!
""
.
equals
(
localIcon
))
{
iconId
=
resources
.
getIdentifier
(
localIcon
,
DRAWABLE
,
packageName
);
Log
.
d
(
LOG_TAG
,
"using icon from plugin options"
);
}
if
(
iconId
==
0
)
{
Log
.
d
(
LOG_TAG
,
"no icon resource found - using default icon"
);
iconId
=
resources
.
getIdentifier
(
"rocket_chat_notification"
,
DRAWABLE
,
packageName
);
}
builder
.
setSmallIcon
(
iconId
);
}
private
void
setNotificationSmallIcon
(
Bundle
extras
,
String
packageName
,
Resources
resources
,
Notification
.
Builder
builder
,
String
localIcon
)
{
int
iconId
=
0
;
String
icon
=
extras
.
getString
(
ICON
);
if
(
icon
!=
null
&&
!
""
.
equals
(
icon
))
{
iconId
=
resources
.
getIdentifier
(
icon
,
DRAWABLE
,
packageName
);
Log
.
d
(
LOG_TAG
,
"using icon from plugin options"
);
}
else
if
(
localIcon
!=
null
&&
!
""
.
equals
(
localIcon
))
{
iconId
=
resources
.
getIdentifier
(
localIcon
,
DRAWABLE
,
packageName
);
Log
.
d
(
LOG_TAG
,
"using icon from plugin options"
);
}
if
(
iconId
==
0
)
{
Log
.
d
(
LOG_TAG
,
"no icon resource found - using default icon"
);
iconId
=
resources
.
getIdentifier
(
"rocket_chat_notification"
,
DRAWABLE
,
packageName
);
}
builder
.
setSmallIcon
(
iconId
);
}
private
void
setNotificationIconColor
(
String
color
,
NotificationCompat
.
Builder
builder
,
String
localIconColor
)
{
int
iconColor
=
0
;
if
(
color
!=
null
&&
!
""
.
equals
(
color
))
{
try
{
iconColor
=
Color
.
parseColor
(
color
);
}
catch
(
IllegalArgumentException
e
)
{
Log
.
e
(
LOG_TAG
,
"couldn't parse color from android options"
);
}
}
else
if
(
localIconColor
!=
null
&&
!
""
.
equals
(
localIconColor
))
{
try
{
iconColor
=
Color
.
parseColor
(
localIconColor
);
}
catch
(
IllegalArgumentException
e
)
{
Log
.
e
(
LOG_TAG
,
"couldn't parse color from android options"
);
}
}
if
(
iconColor
!=
0
)
{
builder
.
setColor
(
iconColor
);
}
}
private
void
updateIntent
(
Intent
intent
,
String
callback
,
Bundle
extras
,
boolean
foreground
,
int
notId
)
{
intent
.
putExtra
(
CALLBACK
,
callback
);
intent
.
putExtra
(
PUSH_BUNDLE
,
extras
);
intent
.
putExtra
(
FOREGROUND
,
foreground
);
intent
.
putExtra
(
NOT_ID
,
notId
);
}
public
Bitmap
getBitmapFromURL
(
String
strURL
,
String
username
,
Context
context
)
{
try
{
URL
url
=
new
URL
(
strURL
);
HttpURLConnection
connection
=
(
HttpURLConnection
)
url
.
openConnection
();
connection
.
setDoInput
(
true
);
connection
.
connect
();
InputStream
input
=
connection
.
getInputStream
();
Bitmap
bitmap
=
BitmapFactory
.
decodeStream
(
input
);
if
(
bitmap
==
null
&&
username
!=
null
&&
context
!=
null
)
{
return
AvatarHelper
.
INSTANCE
.
getTextBitmap
(
username
,
context
);
}
return
bitmap
;
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
return
null
;
}
}
public
static
String
getAppName
(
Context
context
)
{
CharSequence
appName
=
context
.
getPackageManager
()
.
getApplicationLabel
(
context
.
getApplicationInfo
());
return
(
String
)
appName
;
}
private
int
parseInt
(
String
value
,
Bundle
extras
)
{
int
retval
=
0
;
try
{
retval
=
Integer
.
parseInt
(
extras
.
getString
(
value
));
}
catch
(
NumberFormatException
e
)
{
Log
.
e
(
LOG_TAG
,
"Number format exception - Error parsing "
+
value
+
": "
+
e
.
getMessage
());
}
catch
(
Exception
e
)
{
Log
.
e
(
LOG_TAG
,
"Number format exception - Error parsing "
+
value
+
": "
+
e
.
getMessage
());
}
return
retval
;
}
private
Spanned
fromHtml
(
String
source
)
{
if
(
source
!=
null
)
{
return
Html
.
fromHtml
(
source
);
}
else
{
return
null
;
}
}
private
int
extractBadgeCount
(
Bundle
extras
)
{
int
count
=
-
1
;
String
msgcnt
=
extras
.
getString
(
COUNT
);
try
{
if
(
msgcnt
!=
null
)
{
count
=
Integer
.
parseInt
(
msgcnt
);
}
}
catch
(
NumberFormatException
e
)
{
Log
.
e
(
LOG_TAG
,
e
.
getLocalizedMessage
(),
e
);
}
return
count
;
}
private
String
getHostname
(
Bundle
extras
)
{
try
{
JSONObject
jsonObject
=
new
JSONObject
(
extras
.
getString
(
"ejson"
,
"[]"
));
if
(!
jsonObject
.
has
(
"host"
))
{
return
null
;
}
return
ServerPolicyHelper
.
enforceHostname
(
jsonObject
.
getString
(
"host"
));
}
catch
(
Exception
e
)
{
return
null
;
}
}
private
String
getRoomId
(
Bundle
extras
)
{
try
{
JSONObject
jsonObject
=
new
JSONObject
(
extras
.
getString
(
"ejson"
,
"[]"
));
if
(!
jsonObject
.
has
(
"rid"
))
{
return
null
;
}
return
jsonObject
.
getString
(
"rid"
);
}
catch
(
Exception
e
)
{
return
null
;
}
}
private
String
getSenderUsername
(
Bundle
extras
)
{
try
{
JSONObject
jsonObject
=
new
JSONObject
(
extras
.
getString
(
"ejson"
,
"[]"
));
return
jsonObject
.
getJSONObject
(
"sender"
).
optString
(
"username"
);
}
catch
(
JSONException
e
)
{
return
null
;
}
}
private
boolean
isValidHostname
(
Context
context
,
String
hostname
)
{
final
List
<
ServerInfo
>
serverInfoList
=
ConnectivityManager
.
getInstance
(
context
.
getApplicationContext
()).
getServerList
();
for
(
ServerInfo
serverInfo
:
serverInfoList
)
{
if
(
serverInfo
.
getHostname
().
equals
(
hostname
))
{
return
true
;
}
}
return
false
;
}
}
app/src/main/java/chat/rocket/android/push/gcm/GCMIntentService.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
push
.
gcm
;
import
com.google.android.gms.gcm.GcmListenerService
;
import
android.annotation.SuppressLint
;
import
android.content.Context
;
import
android.content.res.Resources
;
import
android.os.Bundle
;
import
android.util.Log
;
import
com.google.android.gms.gcm.GcmListenerService
;
import
org.json.JSONArray
;
import
org.json.JSONException
;
import
org.json.JSONObject
;
import
java.util.ArrayList
;
import
java.util.Iterator
;
import
chat.rocket.android.push.PushConstants
;
import
chat.rocket.android.push.Push
NotificationHandl
er
;
import
chat.rocket.android.push.Push
Manag
er
;
@SuppressLint
(
"NewApi"
)
public
class
GCMIntentService
extends
GcmListenerService
implements
PushConstants
{
...
...
@@ -33,9 +35,7 @@ public class GCMIntentService extends GcmListenerService implements PushConstant
extras
=
normalizeExtras
(
applicationContext
,
extras
);
PushNotificationHandler
pushNotificationHandler
=
new
PushNotificationHandler
();
pushNotificationHandler
.
showNotificationIfPossible
(
applicationContext
,
extras
);
PushManager
.
INSTANCE
.
handle
(
applicationContext
,
extras
);
}
/*
...
...
app/src/main/java/chat/rocket/android/push/gcm/GcmInstanceIDListenerService.java
View file @
5bbd3f7f
...
...
@@ -3,13 +3,14 @@ package chat.rocket.android.push.gcm;
import
com.google.android.gms.iid.InstanceIDListenerService
;
import
java.util.List
;
import
chat.rocket.android.helper.GcmPushSettingHelper
;
import
chat.rocket.persistence.realm.models.ddp.RealmPublicSetting
;
import
chat.rocket.persistence.realm.models.internal.GcmPushRegistration
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.persistence.realm.RealmStore
;
import
chat.rocket.android.service.ConnectivityManager
;
import
chat.rocket.core.models.ServerInfo
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.persistence.realm.RealmStore
;
import
chat.rocket.persistence.realm.models.ddp.RealmPublicSetting
;
import
chat.rocket.persistence.realm.models.internal.GcmPushRegistration
;
public
class
GcmInstanceIDListenerService
extends
InstanceIDListenerService
{
...
...
app/src/main/java/chat/rocket/android/service/ConnectivityManagerApi.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
service
;
import
android.support.annotation.NonNull
;
import
android.support.annotation.Nullable
;
import
java.util.List
;
import
chat.rocket.core.models.ServerInfo
;
import
rx.Observ
able
;
import
r
x.Single
;
import
io.reactivex.Flow
able
;
import
io.reactive
x.Single
;
/**
* interfaces used for Activity/Fragment and other UI-related logic.
*/
public
interface
ConnectivityManagerApi
{
void
keepAliveServer
();
void
keepAliveServer
();
void
addOrUpdateServer
(
String
hostname
,
@Nullable
String
name
,
boolean
insecure
);
void
removeServer
(
String
hostname
);
void
addOrUpdateServer
(
String
hostname
,
@Nullable
String
name
,
boolean
insecur
e
);
Single
<
Boolean
>
connect
(
String
hostnam
e
);
void
removeServer
(
String
hostname
);
List
<
ServerInfo
>
getServerList
(
);
Single
<
Boolean
>
connect
(
String
hostname
);
Flowable
<
ServerConnectivity
>
getServerConnectivityAsObservable
(
);
List
<
ServerInfo
>
getServerList
(
);
int
getConnectivityState
(
@NonNull
String
hostname
);
Observable
<
ServerConnectivity
>
getServerConnectivityAsObservable
();
void
resetConnectivityStateList
();
}
app/src/main/java/chat/rocket/android/service/ConnectivityManagerInternal.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
service
;
import
java.util.List
;
import
chat.rocket.core.models.ServerInfo
;
/**
* interfaces used for RocketChatService and RocketChatwebSocketThread.
*/
/*package*/
interface
ConnectivityManagerInternal
{
int
REASON_CLOSED_BY_USER
=
101
;
int
REASON_NETWORK_ERROR
=
102
;
int
REASON_SERVER_ERROR
=
103
;
int
REASON_UNKNOWN
=
104
;
void
resetConnectivityStateList
();
...
...
app/src/main/java/chat/rocket/android/service/ConnectivityServiceInterface.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
service
;
import
r
x.Single
;
import
io.reactive
x.Single
;
public
interface
ConnectivityServiceInterface
{
Single
<
Boolean
>
ensureConnectionToServer
(
String
hostname
);
...
...
app/src/main/java/chat/rocket/android/service/DDPClientRef.java
deleted
100644 → 0
View file @
1f3713b3
package
chat
.
rocket
.
android
.
service
;
import
chat.rocket.android.api.DDPClientWrapper
;
/**
* reference to get fresh DDPClient instance.
*/
public
interface
DDPClientRef
{
DDPClientWrapper
get
();
}
app/src/main/java/chat/rocket/android/service/RealmBasedConnectivityManager.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
service
;
import
android.annotation.SuppressLint
;
import
android.content.ComponentName
;
import
android.content.Context
;
import
android.content.ServiceConnection
;
import
android.os.IBinder
;
import
android.support.annotation.NonNull
;
import
android.support.annotation.Nullable
;
import
java.util.ArrayList
;
...
...
@@ -12,250 +14,282 @@ import java.util.Map;
import
java.util.concurrent.ConcurrentHashMap
;
import
java.util.concurrent.TimeUnit
;
import
chat.rocket.android.RocketChatCache
;
import
chat.rocket.android.helper.RxHelper
;
import
chat.rocket.android.log.RCLog
;
import
chat.rocket.android_ddp.DDPClient
;
import
chat.rocket.core.models.ServerInfo
;
import
chat.rocket.persistence.realm.models.RealmBasedServerInfo
;
import
hugo.weaving.DebugLog
;
import
rx.Observable
;
import
rx.Single
;
import
rx.subjects.PublishSubject
;
import
io.reactivex.BackpressureStrategy
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
import
io.reactivex.schedulers.Schedulers
;
import
io.reactivex.subjects.BehaviorSubject
;
/**
* Connectivity management implementation.
*/
/*package*/
class
RealmBasedConnectivityManager
implements
ConnectivityManagerApi
,
ConnectivityManagerInternal
{
private
final
ConcurrentHashMap
<
String
,
Integer
>
serverConnectivityList
=
new
ConcurrentHashMap
<>();
private
final
PublishSubject
<
ServerConnectivity
>
connectivitySubject
=
PublishSubject
.
create
();
private
Context
appContext
;
private
final
ServiceConnection
serviceConnection
=
new
ServiceConnection
()
{
implements
ConnectivityManagerApi
,
ConnectivityManagerInternal
{
private
volatile
ConcurrentHashMap
<
String
,
Integer
>
serverConnectivityList
=
new
ConcurrentHashMap
<>();
private
volatile
BehaviorSubject
<
ServerConnectivity
>
connectivitySubject
=
BehaviorSubject
.
createDefault
(
ServerConnectivity
.
CONNECTED
);
private
Context
appContext
;
private
final
ServiceConnection
serviceConnection
=
new
ServiceConnection
()
{
@Override
public
void
onServiceConnected
(
ComponentName
componentName
,
IBinder
binder
)
{
serviceInterface
=
((
RocketChatService
.
LocalBinder
)
binder
).
getServiceInterface
();
}
@Override
public
void
onServiceDisconnected
(
ComponentName
componentName
)
{
serviceInterface
=
null
;
}
};
private
ConnectivityServiceInterface
serviceInterface
;
/*package*/
RealmBasedConnectivityManager
setContext
(
Context
appContext
)
{
this
.
appContext
=
appContext
.
getApplicationContext
();
return
this
;
}
@Override
public
void
resetConnectivityStateList
()
{
serverConnectivityList
.
clear
();
for
(
ServerInfo
serverInfo
:
RealmBasedServerInfo
.
getServerInfoList
())
{
serverConnectivityList
.
put
(
serverInfo
.
getHostname
(),
ServerConnectivity
.
STATE_DISCONNECTED
);
}
}
@Override
public
void
onServiceConnected
(
ComponentName
componentName
,
IBinder
binder
)
{
serviceInterface
=
((
RocketChatService
.
LocalBinder
)
binder
).
getServiceInterface
();
public
void
keepAliveServer
()
{
RocketChatService
.
keepAlive
(
appContext
);
if
(
serviceInterface
==
null
)
{
RocketChatService
.
bind
(
appContext
,
serviceConnection
);
}
}
@SuppressLint
(
"RxLeakedSubscription"
)
@DebugLog
@Override
public
void
onServiceDisconnected
(
ComponentName
componentName
)
{
serviceInterface
=
null
;
public
void
ensureConnections
()
{
String
hostname
=
new
RocketChatCache
(
appContext
).
getSelectedServerHostname
();
if
(
hostname
==
null
)
{
return
;
}
connectToServerIfNeeded
(
hostname
,
true
/* force connect */
)
.
subscribeOn
(
Schedulers
.
io
())
.
subscribe
(
connected
->
{
if
(!
connected
)
{
notifyConnectionLost
(
hostname
,
DDPClient
.
REASON_NETWORK_ERROR
);
}
},
error
->
{
RCLog
.
e
(
error
);
notifyConnectionLost
(
hostname
,
DDPClient
.
REASON_NETWORK_ERROR
);
});
}
};
private
ConnectivityServiceInterface
serviceInterface
;
@SuppressLint
(
"RxLeakedSubscription"
)
@Override
public
void
addOrUpdateServer
(
String
hostname
,
@Nullable
String
name
,
boolean
insecure
)
{
RealmBasedServerInfo
.
addOrUpdate
(
hostname
,
name
,
insecure
);
if
(!
serverConnectivityList
.
containsKey
(
hostname
))
{
serverConnectivityList
.
put
(
hostname
,
ServerConnectivity
.
STATE_DISCONNECTED
);
}
connectToServerIfNeeded
(
hostname
,
false
)
.
subscribe
(
connected
->
{
},
RCLog:
:
e
);
}
/*package*/
RealmBasedConnectivityManager
setContext
(
Context
appContext
)
{
this
.
appContext
=
appContext
.
getApplicationContext
();
return
this
;
}
@SuppressLint
(
"RxLeakedSubscription"
)
@Override
public
void
removeServer
(
String
hostname
)
{
RealmBasedServerInfo
.
remove
(
hostname
);
if
(
serverConnectivityList
.
containsKey
(
hostname
))
{
disconnectFromServerIfNeeded
(
hostname
)
.
subscribe
(
_val
->
{
},
RCLog:
:
e
);
}
}
@Override
public
void
resetConnectivityStateList
()
{
serverConnectivityList
.
clear
();
for
(
ServerInfo
serverInfo
:
RealmBasedServerInfo
.
getServerInfoList
())
{
serverConnectivityList
.
put
(
serverInfo
.
getHostname
(),
ServerConnectivity
.
STATE_DISCONNECTED
);
@Override
public
Single
<
Boolean
>
connect
(
String
hostname
)
{
return
connectToServerIfNeeded
(
hostname
,
false
);
}
}
@Override
public
void
keepAliveServer
()
{
RocketChatService
.
keepAlive
(
appContext
);
if
(
serviceInterface
==
null
)
{
RocketChatService
.
bind
(
appContext
,
serviceConnection
);
@Override
public
List
<
ServerInfo
>
getServerList
()
{
return
RealmBasedServerInfo
.
getServerInfoList
();
}
}
@DebugLog
@Override
public
void
ensureConnections
()
{
for
(
String
hostname
:
serverConnectivityList
.
keySet
())
{
connectToServerIfNeeded
(
hostname
,
true
/* force connect */
)
.
subscribe
(
_val
->
{
},
RCLog:
:
e
);
@Override
public
ServerInfo
getServerInfoForHost
(
String
hostname
)
{
return
RealmBasedServerInfo
.
getServerInfoForHost
(
hostname
);
}
}
@Override
public
void
addOrUpdateServer
(
String
hostname
,
@Nullable
String
name
,
boolean
insecure
)
{
RealmBasedServerInfo
.
addOrUpdate
(
hostname
,
name
,
insecure
);
if
(!
serverConnectivityList
.
containsKey
(
hostname
))
{
serverConnectivityList
.
put
(
hostname
,
ServerConnectivity
.
STATE_DISCONNECTED
);
private
List
<
ServerConnectivity
>
getCurrentConnectivityList
()
{
ArrayList
<
ServerConnectivity
>
list
=
new
ArrayList
<>();
for
(
Map
.
Entry
<
String
,
Integer
>
entry
:
serverConnectivityList
.
entrySet
())
{
list
.
add
(
new
ServerConnectivity
(
entry
.
getKey
(),
entry
.
getValue
()));
}
return
list
;
}
connectToServerIfNeeded
(
hostname
,
false
)
.
subscribe
(
_val
->
{
},
RCLog:
:
e
);
}
@Override
public
void
removeServer
(
String
hostname
)
{
RealmBasedServerInfo
.
remove
(
hostname
);
if
(
serverConnectivityList
.
containsKey
(
hostname
))
{
disconnectFromServerIfNeeded
(
hostname
)
.
subscribe
(
_val
->
{
},
RCLog:
:
e
);
@DebugLog
@Override
public
void
notifyConnectionEstablished
(
String
hostname
,
String
session
)
{
if
(
session
!=
null
)
{
RealmBasedServerInfo
.
updateSession
(
hostname
,
session
);
}
serverConnectivityList
.
put
(
hostname
,
ServerConnectivity
.
STATE_CONNECTED
);
connectivitySubject
.
onNext
(
new
ServerConnectivity
(
hostname
,
ServerConnectivity
.
STATE_CONNECTED
));
}
}
@Override
public
Single
<
Boolean
>
connect
(
String
hostname
)
{
return
connectToServerIfNeeded
(
hostname
,
false
);
}
@Override
public
List
<
ServerInfo
>
getServerList
()
{
return
RealmBasedServerInfo
.
getServerInfoList
();
}
@Override
public
ServerInfo
getServerInfoForHost
(
String
hostname
)
{
return
RealmBasedServerInfo
.
getServerInfoForHost
(
hostname
);
}
private
List
<
ServerConnectivity
>
getCurrentConnectivityList
()
{
ArrayList
<
ServerConnectivity
>
list
=
new
ArrayList
<>();
for
(
Map
.
Entry
<
String
,
Integer
>
entry
:
serverConnectivityList
.
entrySet
())
{
list
.
add
(
new
ServerConnectivity
(
entry
.
getKey
(),
entry
.
getValue
()));
@DebugLog
@Override
public
void
notifyConnectionLost
(
String
hostname
,
int
code
)
{
serverConnectivityList
.
put
(
hostname
,
ServerConnectivity
.
STATE_DISCONNECTED
);
connectivitySubject
.
onNext
(
new
ServerConnectivity
(
hostname
,
ServerConnectivity
.
STATE_DISCONNECTED
,
code
));
}
return
list
;
}
@DebugLog
@Override
public
void
notifyConnectionEstablished
(
String
hostname
,
String
session
)
{
RealmBasedServerInfo
.
updateSession
(
hostname
,
session
);
serverConnectivityList
.
put
(
hostname
,
ServerConnectivity
.
STATE_CONNECTED
);
connectivitySubject
.
onNext
(
new
ServerConnectivity
(
hostname
,
ServerConnectivity
.
STATE_CONNECTED
));
}
@DebugLog
@Override
public
void
notifyConnectionLost
(
String
hostname
,
int
reason
)
{
serverConnectivityList
.
put
(
hostname
,
ServerConnectivity
.
STATE_DISCONNECTED
);
connectivitySubject
.
onNext
(
new
ServerConnectivity
(
hostname
,
ServerConnectivity
.
STATE_DISCONNECTED
));
}
@DebugLog
@Override
public
void
notifyConnecting
(
String
hostname
)
{
serverConnectivityList
.
put
(
hostname
,
ServerConnectivity
.
STATE_CONNECTING
);
connectivitySubject
.
onNext
(
new
ServerConnectivity
(
hostname
,
ServerConnectivity
.
STATE_CONNECTING
));
}
@Override
public
Observable
<
ServerConnectivity
>
getServerConnectivityAsObservable
()
{
return
Observable
.
concat
(
Observable
.
from
(
getCurrentConnectivityList
()),
connectivitySubject
);
}
@DebugLog
private
Single
<
Boolean
>
connectToServerIfNeeded
(
String
hostname
,
boolean
forceConnect
)
{
return
Single
.
defer
(()
->
{
final
int
connectivity
=
serverConnectivityList
.
get
(
hostname
);
if
(!
forceConnect
&&
connectivity
==
ServerConnectivity
.
STATE_CONNECTED
)
{
return
Single
.
just
(
true
);
}
if
(
connectivity
==
ServerConnectivity
.
STATE_DISCONNECTING
)
{
return
waitForDisconnected
(
hostname
)
.
flatMap
(
_val
->
connectToServerIfNeeded
(
hostname
,
forceConnect
));
}
if
(
connectivity
==
ServerConnectivity
.
STATE_CONNECTING
)
{
return
waitForConnected
(
hostname
);
}
return
connectToServer
(
hostname
)
.
doOnError
(
RCLog:
:
e
)
.
retryWhen
(
RxHelper
.
exponentialBackoff
(
Integer
.
MAX_VALUE
,
500
,
TimeUnit
.
MILLISECONDS
));
});
}
private
Single
<
Boolean
>
disconnectFromServerIfNeeded
(
String
hostname
)
{
return
Single
.
defer
(()
->
{
final
int
connectivity
=
serverConnectivityList
.
get
(
hostname
);
if
(
connectivity
==
ServerConnectivity
.
STATE_DISCONNECTED
)
{
return
Single
.
just
(
true
);
}
if
(
connectivity
==
ServerConnectivity
.
STATE_CONNECTING
)
{
return
waitForConnected
(
hostname
)
.
onErrorReturn
(
err
->
true
)
.
flatMap
(
_val
->
disconnectFromServerIfNeeded
(
hostname
));
}
if
(
connectivity
==
ServerConnectivity
.
STATE_DISCONNECTING
)
{
return
waitForDisconnected
(
hostname
);
}
return
disconnectFromServer
(
hostname
)
//.doOnError(RCLog::e)
.
retryWhen
(
RxHelper
.
exponentialBackoff
(
3
,
500
,
TimeUnit
.
MILLISECONDS
));
});
}
@DebugLog
private
Single
<
Boolean
>
waitForConnected
(
String
hostname
)
{
return
connectivitySubject
.
filter
(
serverConnectivity
->
hostname
.
equals
(
serverConnectivity
.
hostname
))
.
map
(
serverConnectivity
->
serverConnectivity
.
state
)
.
filter
(
state
->
state
==
ServerConnectivity
.
STATE_CONNECTED
||
state
==
ServerConnectivity
.
STATE_DISCONNECTED
)
.
first
()
.
toSingle
()
.
flatMap
(
state
->
state
==
ServerConnectivity
.
STATE_CONNECTED
?
Single
.
just
(
true
)
:
Single
.
error
(
new
ServerConnectivity
.
DisconnectedException
()));
}
@DebugLog
private
Single
<
Boolean
>
waitForDisconnected
(
String
hostname
)
{
return
connectivitySubject
.
filter
(
serverConnectivity
->
hostname
.
equals
(
serverConnectivity
.
hostname
))
.
map
(
serverConnectivity
->
serverConnectivity
.
state
)
.
filter
(
state
->
state
==
ServerConnectivity
.
STATE_DISCONNECTED
)
.
first
()
.
toSingle
()
.
map
(
state
->
true
);
}
@DebugLog
private
Single
<
Boolean
>
connectToServer
(
String
hostname
)
{
return
Single
.
defer
(()
->
{
if
(!
serverConnectivityList
.
containsKey
(
hostname
))
{
return
Single
.
error
(
new
IllegalArgumentException
(
"hostname not found"
));
}
if
(
serverConnectivityList
.
get
(
hostname
)
!=
ServerConnectivity
.
STATE_CONNECTED
)
{
// Mark as CONNECTING except for the case [forceConnect && connected] because
// ensureConnectionToServer doesn't notify ConnectionEstablished/Lost is already connected.
@DebugLog
@Override
public
void
notifyConnecting
(
String
hostname
)
{
serverConnectivityList
.
put
(
hostname
,
ServerConnectivity
.
STATE_CONNECTING
);
}
if
(
serviceInterface
!=
null
)
{
return
serviceInterface
.
ensureConnectionToServer
(
hostname
);
}
else
{
return
Single
.
error
(
new
IllegalStateException
(
"not prepared"
));
}
});
}
private
Single
<
Boolean
>
disconnectFromServer
(
String
hostname
)
{
return
Single
.
defer
(()
->
{
if
(!
serverConnectivityList
.
containsKey
(
hostname
))
{
return
Single
.
error
(
new
IllegalArgumentException
(
"hostname not found"
));
}
serverConnectivityList
.
put
(
hostname
,
ServerConnectivity
.
STATE_DISCONNECTING
);
if
(
serviceInterface
!=
null
)
{
return
serviceInterface
.
disconnectFromServer
(
hostname
)
// //after disconnection from server, remove HOSTNAME key from HashMap
.
doAfterTerminate
(()
->
serverConnectivityList
.
remove
(
hostname
));
}
else
{
return
Single
.
error
(
new
IllegalStateException
(
"not prepared"
));
}
});
}
connectivitySubject
.
onNext
(
new
ServerConnectivity
(
hostname
,
ServerConnectivity
.
STATE_CONNECTING
));
}
@Override
public
Flowable
<
ServerConnectivity
>
getServerConnectivityAsObservable
()
{
return
connectivitySubject
.
toFlowable
(
BackpressureStrategy
.
LATEST
);
}
@Override
public
int
getConnectivityState
(
@NonNull
String
hostname
)
{
return
serverConnectivityList
.
get
(
hostname
);
}
@DebugLog
private
Single
<
Boolean
>
connectToServerIfNeeded
(
String
hostname
,
boolean
forceConnect
)
{
return
Single
.
defer
(()
->
{
Integer
state
=
serverConnectivityList
.
get
(
hostname
);
if
(
state
==
null
)
{
state
=
ServerConnectivity
.
STATE_DISCONNECTED
;
}
final
int
connectivity
=
state
;
if
(!
forceConnect
&&
connectivity
==
ServerConnectivity
.
STATE_CONNECTED
)
{
return
Single
.
just
(
true
);
}
if
(
connectivity
==
ServerConnectivity
.
STATE_DISCONNECTING
)
{
return
waitForDisconnected
(
hostname
)
.
flatMap
(
_val
->
connectToServerIfNeeded
(
hostname
,
forceConnect
));
}
if
(
connectivity
==
ServerConnectivity
.
STATE_DISCONNECTED
)
{
// notifyConnecting(hostname);
}
return
connectToServer
(
hostname
)
.
retry
(
exception
->
exception
instanceof
ThreadLooperNotPreparedException
)
.
onErrorResumeNext
(
Single
.
just
(
false
));
});
}
private
Single
<
Boolean
>
disconnectFromServerIfNeeded
(
String
hostname
)
{
return
Single
.
defer
(()
->
{
final
int
connectivity
=
serverConnectivityList
.
get
(
hostname
);
if
(
connectivity
==
ServerConnectivity
.
STATE_DISCONNECTED
)
{
return
Single
.
just
(
true
);
}
if
(
connectivity
==
ServerConnectivity
.
STATE_CONNECTING
)
{
return
waitForConnected
(
hostname
)
.
doOnError
(
err
->
notifyConnectionLost
(
hostname
,
DDPClient
.
REASON_NETWORK_ERROR
))
.
flatMap
(
_val
->
disconnectFromServerIfNeeded
(
hostname
));
}
if
(
connectivity
==
ServerConnectivity
.
STATE_DISCONNECTING
)
{
return
waitForDisconnected
(
hostname
);
}
return
disconnectFromServer
(
hostname
)
.
retryWhen
(
RxHelper
.
exponentialBackoff
(
1
,
500
,
TimeUnit
.
MILLISECONDS
));
});
}
@DebugLog
private
Single
<
Boolean
>
waitForConnected
(
String
hostname
)
{
return
connectivitySubject
.
filter
(
serverConnectivity
->
hostname
.
equals
(
serverConnectivity
.
hostname
))
.
map
(
serverConnectivity
->
serverConnectivity
.
state
)
.
filter
(
state
->
state
==
ServerConnectivity
.
STATE_CONNECTED
||
state
==
ServerConnectivity
.
STATE_DISCONNECTED
)
.
firstElement
()
.
toSingle
()
.
flatMap
(
state
->
state
==
ServerConnectivity
.
STATE_CONNECTED
?
Single
.
just
(
true
)
:
Single
.
error
(
new
ServerConnectivity
.
DisconnectedException
()));
}
@DebugLog
private
Single
<
Boolean
>
waitForDisconnected
(
String
hostname
)
{
return
connectivitySubject
.
filter
(
serverConnectivity
->
hostname
.
equals
(
serverConnectivity
.
hostname
))
.
map
(
serverConnectivity
->
serverConnectivity
.
state
)
.
filter
(
state
->
state
==
ServerConnectivity
.
STATE_DISCONNECTED
)
.
firstElement
()
.
toSingle
()
.
map
(
state
->
true
);
}
@DebugLog
private
Single
<
Boolean
>
connectToServer
(
String
hostname
)
{
return
Single
.
defer
(()
->
{
if
(!
serverConnectivityList
.
containsKey
(
hostname
))
{
return
Single
.
error
(
new
IllegalArgumentException
(
"hostname not found"
));
}
if
(
serverConnectivityList
.
get
(
hostname
)
!=
ServerConnectivity
.
STATE_CONNECTED
)
{
// Mark as CONNECTING except for the case [forceConnect && connected] because
// ensureConnectionToServer doesn't notify ConnectionEstablished/Lost is already connected.
// serverConnectivityList.put(hostname, ServerConnectivity.STATE_CONNECTING);
}
if
(
serviceInterface
!=
null
)
{
return
serviceInterface
.
ensureConnectionToServer
(
hostname
);
}
else
{
return
Single
.
error
(
new
ThreadLooperNotPreparedException
(
"not prepared"
));
}
});
}
private
Single
<
Boolean
>
disconnectFromServer
(
String
hostname
)
{
return
Single
.
defer
(()
->
{
if
(!
serverConnectivityList
.
containsKey
(
hostname
))
{
return
Single
.
error
(
new
IllegalArgumentException
(
"hostname not found"
));
}
serverConnectivityList
.
put
(
hostname
,
ServerConnectivity
.
STATE_DISCONNECTING
);
if
(
serviceInterface
!=
null
)
{
return
serviceInterface
.
disconnectFromServer
(
hostname
)
// //after disconnection from server, remove HOSTNAME key from HashMap
.
doAfterTerminate
(()
->
serverConnectivityList
.
remove
(
hostname
));
}
else
{
return
Single
.
error
(
new
IllegalStateException
(
"not prepared"
));
}
});
}
private
static
class
ThreadLooperNotPreparedException
extends
IllegalStateException
{
ThreadLooperNotPreparedException
(
String
message
)
{
super
(
message
);
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/service/RocketChatService.java
View file @
5bbd3f7f
...
...
@@ -8,123 +8,145 @@ import android.os.Binder;
import
android.os.IBinder
;
import
android.support.annotation.Nullable
;
import
java.util.HashMap
;
import
java.util.concurrent.Semaphore
;
import
java.util.concurrent.TimeUnit
;
import
chat.rocket.android.helper.Logger
;
import
chat.rocket.android.log.RCLog
;
import
chat.rocket.persistence.realm.RealmStore
;
import
hugo.weaving.DebugLog
;
import
r
x.Observable
;
import
r
x.Single
;
import
io.reactive
x.Observable
;
import
io.reactive
x.Single
;
/**
* Background service for Rocket.Chat.Application class.
*/
public
class
RocketChatService
extends
Service
implements
ConnectivityServiceInterface
{
private
ConnectivityManagerInternal
connectivityManager
;
private
HashMap
<
String
,
RocketChatWebSocketThread
>
webSocketThreads
;
private
Semaphore
webSocketThreadLock
=
new
Semaphore
(
1
)
;
private
ConnectivityManagerInternal
connectivityManager
;
private
static
volatile
Semaphore
webSocketThreadLock
=
new
Semaphore
(
1
)
;
private
static
volatile
RocketChatWebSocketThread
currentWebSocketThread
;
public
class
LocalBinder
extends
Binder
{
ConnectivityServiceInterface
getServiceInterface
()
{
return
RocketChatService
.
this
;
public
class
LocalBinder
extends
Binder
{
ConnectivityServiceInterface
getServiceInterface
()
{
return
RocketChatService
.
this
;
}
}
private
final
LocalBinder
localBinder
=
new
LocalBinder
();
/**
* ensure RocketChatService alive.
*/
/*package*/
static
void
keepAlive
(
Context
context
)
{
context
.
startService
(
new
Intent
(
context
,
RocketChatService
.
class
));
}
public
static
void
bind
(
Context
context
,
ServiceConnection
serviceConnection
)
{
context
.
bindService
(
new
Intent
(
context
,
RocketChatService
.
class
),
serviceConnection
,
Context
.
BIND_AUTO_CREATE
);
}
public
static
void
unbind
(
Context
context
,
ServiceConnection
serviceConnection
)
{
context
.
unbindService
(
serviceConnection
);
}
@DebugLog
@Override
public
void
onCreate
()
{
super
.
onCreate
();
connectivityManager
=
ConnectivityManager
.
getInstanceForInternal
(
getApplicationContext
());
connectivityManager
.
resetConnectivityStateList
();
}
@DebugLog
@Override
public
int
onStartCommand
(
Intent
intent
,
int
flags
,
int
startId
)
{
connectivityManager
.
ensureConnections
();
return
START_NOT_STICKY
;
}
@Override
public
Single
<
Boolean
>
ensureConnectionToServer
(
String
hostname
)
{
//called via binder.
return
getOrCreateWebSocketThread
(
hostname
)
.
flatMap
(
RocketChatWebSocketThread:
:
keepAlive
);
}
@Override
public
Single
<
Boolean
>
disconnectFromServer
(
String
hostname
)
{
//called via binder.
return
Single
.
defer
(()
->
{
if
(!
existsThreadForHostname
(
hostname
))
{
return
Single
.
just
(
true
);
}
if
(
currentWebSocketThread
!=
null
)
{
return
currentWebSocketThread
.
terminate
()
// after disconnection from server
.
doAfterTerminate
(()
->
{
currentWebSocketThread
=
null
;
// remove RealmConfiguration key from HashMap
RealmStore
.
sStore
.
remove
(
hostname
);
});
}
else
{
return
Observable
.
timer
(
1
,
TimeUnit
.
SECONDS
).
singleOrError
()
.
flatMap
(
_val
->
disconnectFromServer
(
hostname
));
}
});
}
@DebugLog
private
Single
<
RocketChatWebSocketThread
>
getOrCreateWebSocketThread
(
String
hostname
)
{
return
Single
.
defer
(()
->
{
webSocketThreadLock
.
acquire
();
int
connectivityState
=
ConnectivityManager
.
getInstance
(
getApplicationContext
()).
getConnectivityState
(
hostname
);
boolean
isDisconnected
=
connectivityState
!=
ServerConnectivity
.
STATE_CONNECTED
;
if
(
currentWebSocketThread
!=
null
&&
existsThreadForHostname
(
hostname
)
&&
!
isDisconnected
)
{
webSocketThreadLock
.
release
();
return
Single
.
just
(
currentWebSocketThread
);
}
if
(
currentWebSocketThread
!=
null
)
{
return
currentWebSocketThread
.
terminate
()
.
doAfterTerminate
(()
->
currentWebSocketThread
=
null
)
.
flatMap
(
terminated
->
RocketChatWebSocketThread
.
getStarted
(
getApplicationContext
(),
hostname
)
.
doOnSuccess
(
thread
->
{
currentWebSocketThread
=
thread
;
webSocketThreadLock
.
release
();
})
.
doOnError
(
throwable
->
{
currentWebSocketThread
=
null
;
RCLog
.
e
(
throwable
);
Logger
.
report
(
throwable
);
webSocketThreadLock
.
release
();
})
);
}
return
RocketChatWebSocketThread
.
getStarted
(
getApplicationContext
(),
hostname
)
.
doOnSuccess
(
thread
->
{
currentWebSocketThread
=
thread
;
webSocketThreadLock
.
release
();
})
.
doOnError
(
throwable
->
{
currentWebSocketThread
=
null
;
RCLog
.
e
(
throwable
);
Logger
.
report
(
throwable
);
webSocketThreadLock
.
release
();
});
});
}
private
boolean
existsThreadForHostname
(
String
hostname
)
{
if
(
hostname
==
null
||
currentWebSocketThread
==
null
)
{
return
false
;
}
return
currentWebSocketThread
.
getName
().
equals
(
"RC_thread_"
+
hostname
);
}
@Nullable
@Override
public
IBinder
onBind
(
Intent
intent
)
{
return
localBinder
;
}
}
private
final
LocalBinder
localBinder
=
new
LocalBinder
();
/**
* ensure RocketChatService alive.
*/
/*package*/
static
void
keepAlive
(
Context
context
)
{
context
.
startService
(
new
Intent
(
context
,
RocketChatService
.
class
));
}
public
static
void
bind
(
Context
context
,
ServiceConnection
serviceConnection
)
{
context
.
bindService
(
new
Intent
(
context
,
RocketChatService
.
class
),
serviceConnection
,
Context
.
BIND_AUTO_CREATE
);
}
public
static
void
unbind
(
Context
context
,
ServiceConnection
serviceConnection
)
{
context
.
unbindService
(
serviceConnection
);
}
@DebugLog
@Override
public
void
onCreate
()
{
super
.
onCreate
();
connectivityManager
=
ConnectivityManager
.
getInstanceForInternal
(
getApplicationContext
());
connectivityManager
.
resetConnectivityStateList
();
webSocketThreads
=
new
HashMap
<>();
}
@DebugLog
@Override
public
int
onStartCommand
(
Intent
intent
,
int
flags
,
int
startId
)
{
connectivityManager
.
ensureConnections
();
return
START_NOT_STICKY
;
}
@Override
public
Single
<
Boolean
>
ensureConnectionToServer
(
String
hostname
)
{
//called via binder.
return
getOrCreateWebSocketThread
(
hostname
)
.
doOnError
(
err
->
{
webSocketThreads
.
remove
(
hostname
);
connectivityManager
.
notifyConnectionLost
(
hostname
,
ConnectivityManagerInternal
.
REASON_NETWORK_ERROR
);
})
.
flatMap
(
webSocketThreads
->
webSocketThreads
.
keepAlive
());
}
@Override
public
Single
<
Boolean
>
disconnectFromServer
(
String
hostname
)
{
//called via binder.
return
Single
.
defer
(()
->
{
if
(!
webSocketThreads
.
containsKey
(
hostname
))
{
return
Single
.
just
(
true
);
}
RocketChatWebSocketThread
thread
=
webSocketThreads
.
get
(
hostname
);
if
(
thread
!=
null
)
{
return
thread
.
terminate
()
// after disconnection from server
.
doAfterTerminate
(()
->
{
// remove RCWebSocket key from HashMap
webSocketThreads
.
remove
(
hostname
);
// remove RealmConfiguration key from HashMap
RealmStore
.
sStore
.
remove
(
hostname
);
});
}
else
{
return
Observable
.
timer
(
1
,
TimeUnit
.
SECONDS
).
toSingle
()
.
flatMap
(
_val
->
disconnectFromServer
(
hostname
));
}
});
}
@DebugLog
private
Single
<
RocketChatWebSocketThread
>
getOrCreateWebSocketThread
(
String
hostname
)
{
return
Single
.
defer
(()
->
{
webSocketThreadLock
.
acquire
();
if
(
webSocketThreads
.
containsKey
(
hostname
))
{
RocketChatWebSocketThread
thread
=
webSocketThreads
.
get
(
hostname
);
webSocketThreadLock
.
release
();
return
Single
.
just
(
thread
);
}
return
RocketChatWebSocketThread
.
getStarted
(
getApplicationContext
(),
hostname
)
.
doOnSuccess
(
thread
->
{
webSocketThreads
.
put
(
hostname
,
thread
);
webSocketThreadLock
.
release
();
})
.
doOnError
(
throwable
->
{
Logger
.
report
(
throwable
);
webSocketThreadLock
.
release
();
});
});
}
@Nullable
@Override
public
IBinder
onBind
(
Intent
intent
)
{
return
localBinder
;
}
}
app/src/main/java/chat/rocket/android/service/RocketChatWebSocketThread.java
View file @
5bbd3f7f
...
...
@@ -11,9 +11,9 @@ import java.util.ArrayList;
import
java.util.Iterator
;
import
java.util.List
;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.TimeoutException
;
import
bolts.Task
;
import
chat.rocket.android.api.DDPClientWrapper
;
import
chat.rocket.android.api.MethodCallHelper
;
import
chat.rocket.android.helper.LogIfError
;
import
chat.rocket.android.helper.RxHelper
;
...
...
@@ -23,6 +23,7 @@ import chat.rocket.android.service.ddp.base.ActiveUsersSubscriber;
import
chat.rocket.android.service.ddp.base.LoginServiceConfigurationSubscriber
;
import
chat.rocket.android.service.ddp.base.UserDataSubscriber
;
import
chat.rocket.android.service.observer.CurrentUserObserver
;
import
chat.rocket.android.service.observer.DeletedMessageObserver
;
import
chat.rocket.android.service.observer.FileUploadingToUrlObserver
;
import
chat.rocket.android.service.observer.FileUploadingWithUfsObserver
;
import
chat.rocket.android.service.observer.GcmPushRegistrationObserver
;
...
...
@@ -32,433 +33,391 @@ import chat.rocket.android.service.observer.MethodCallObserver;
import
chat.rocket.android.service.observer.NewMessageObserver
;
import
chat.rocket.android.service.observer.PushSettingsObserver
;
import
chat.rocket.android.service.observer.SessionObserver
;
import
chat.rocket.android_ddp.DDPClient
;
import
chat.rocket.android_ddp.DDPClientCallback
;
import
chat.rocket.android_ddp.rx.RxWebSocketCallback
;
import
chat.rocket.core.models.ServerInfo
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.persistence.realm.RealmStore
;
import
chat.rocket.persistence.realm.models.internal.RealmSession
;
import
hugo.weaving.DebugLog
;
import
io.reactivex.Completable
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
import
io.reactivex.disposables.CompositeDisposable
;
import
rx.Completable
;
import
rx.Single
;
import
rx.subscriptions.CompositeSubscription
;
/**
* Thread for handling WebSocket connection.
*/
public
class
RocketChatWebSocketThread
extends
HandlerThread
{
private
static
final
Class
[]
REGISTERABLE_CLASSES
=
{
LoginServiceConfigurationSubscriber
.
class
,
ActiveUsersSubscriber
.
class
,
UserDataSubscriber
.
class
,
MethodCallObserver
.
class
,
SessionObserver
.
class
,
LoadMessageProcedureObserver
.
class
,
GetUsersOfRoomsProcedureObserver
.
class
,
NewMessageObserver
.
class
,
CurrentUserObserver
.
class
,
FileUploadingToUrlObserver
.
class
,
FileUploadingWithUfsObserver
.
class
,
PushSettingsObserver
.
class
,
GcmPushRegistrationObserver
.
class
};
private
static
final
long
HEARTBEAT_PERIOD_MS
=
20000
;
private
final
Context
appContext
;
private
final
String
hostname
;
private
final
RealmHelper
realmHelper
;
private
final
ConnectivityManagerInternal
connectivityManager
;
private
final
ArrayList
<
Registrable
>
listeners
=
new
ArrayList
<>();
private
final
CompositeDisposable
hearbeatDisposable
=
new
CompositeDisposable
();
private
final
CompositeSubscription
reconnectSubscription
=
new
CompositeSubscription
();
private
DDPClientWrapper
ddpClient
;
private
boolean
listenersRegistered
;
private
final
DDPClientRef
ddpClientRef
=
new
DDPClientRef
()
{
private
static
final
Class
[]
REGISTERABLE_CLASSES
=
{
LoginServiceConfigurationSubscriber
.
class
,
ActiveUsersSubscriber
.
class
,
UserDataSubscriber
.
class
,
MethodCallObserver
.
class
,
SessionObserver
.
class
,
LoadMessageProcedureObserver
.
class
,
GetUsersOfRoomsProcedureObserver
.
class
,
NewMessageObserver
.
class
,
DeletedMessageObserver
.
class
,
CurrentUserObserver
.
class
,
FileUploadingToUrlObserver
.
class
,
FileUploadingWithUfsObserver
.
class
,
PushSettingsObserver
.
class
,
GcmPushRegistrationObserver
.
class
};
private
static
final
long
HEARTBEAT_PERIOD_MS
=
20000
;
private
final
Context
appContext
;
private
final
String
hostname
;
private
final
RealmHelper
realmHelper
;
private
final
ConnectivityManagerInternal
connectivityManager
;
private
final
ArrayList
<
Registrable
>
listeners
=
new
ArrayList
<>();
private
final
CompositeDisposable
heartbeatDisposable
=
new
CompositeDisposable
();
private
final
CompositeDisposable
reconnectDisposable
=
new
CompositeDisposable
();
private
boolean
listenersRegistered
;
private
RocketChatWebSocketThread
(
Context
appContext
,
String
hostname
)
{
super
(
"RC_thread_"
+
hostname
);
this
.
appContext
=
appContext
;
this
.
hostname
=
hostname
;
this
.
realmHelper
=
RealmStore
.
getOrCreate
(
hostname
);
this
.
connectivityManager
=
ConnectivityManager
.
getInstanceForInternal
(
appContext
);
}
/**
* build new Thread.
*/
@DebugLog
/* package */
static
Single
<
RocketChatWebSocketThread
>
getStarted
(
Context
appContext
,
String
hostname
)
{
return
Single
.<
RocketChatWebSocketThread
>
create
(
objectSingleEmitter
->
{
new
RocketChatWebSocketThread
(
appContext
,
hostname
)
{
@Override
protected
void
onLooperPrepared
()
{
try
{
super
.
onLooperPrepared
();
objectSingleEmitter
.
onSuccess
(
this
);
}
catch
(
Exception
exception
)
{
objectSingleEmitter
.
onError
(
exception
);
}
}
}.
start
();
}).
flatMap
(
webSocket
->
webSocket
.
connectWithExponentialBackoff
().
map
(
_val
->
webSocket
));
}
@Override
public
DDPClientWrapper
get
()
{
return
ddpClient
;
protected
void
onLooperPrepared
()
{
super
.
onLooperPrepared
();
forceInvalidateTokens
();
}
};
private
static
class
KeepAliveTimer
{
private
long
lastTime
;
private
final
long
thresholdMs
;
private
void
forceInvalidateTokens
()
{
realmHelper
.
executeTransaction
(
realm
->
{
RealmSession
session
=
RealmSession
.
queryDefaultSession
(
realm
).
findFirst
();
if
(
session
!=
null
&&
!
TextUtils
.
isEmpty
(
session
.
getToken
())
&&
(
session
.
isTokenVerified
()
||
!
TextUtils
.
isEmpty
(
session
.
getError
())))
{
session
.
setTokenVerified
(
false
);
session
.
setError
(
null
);
}
return
null
;
}).
continueWith
(
new
LogIfError
());
}
public
KeepAliveTimer
(
long
thresholdMs
)
{
this
.
thresholdMs
=
thresholdMs
;
lastTime
=
System
.
currentTimeMillis
();
/**
* terminate WebSocket thread.
*/
@DebugLog
/* package */
Single
<
Boolean
>
terminate
()
{
if
(
isAlive
())
{
return
Single
.
create
(
emitter
->
{
new
Handler
(
getLooper
()).
post
(()
->
{
RCLog
.
d
(
"thread %s: terminated()"
,
Thread
.
currentThread
().
getId
());
unregisterListenersAndClose
();
connectivityManager
.
notifyConnectionLost
(
hostname
,
DDPClient
.
REASON_CLOSED_BY_USER
);
RocketChatWebSocketThread
.
super
.
quit
();
emitter
.
onSuccess
(
true
);
});
});
}
else
{
connectivityManager
.
notifyConnectionLost
(
hostname
,
DDPClient
.
REASON_NETWORK_ERROR
);
super
.
quit
();
return
Single
.
just
(
true
);
}
}
public
boolean
shouldCheckPrecisely
()
{
return
lastTime
+
thresholdMs
<
System
.
currentTimeMillis
();
/**
* THIS METHOD THROWS EXCEPTION!! Use terminate() instead!!
*/
@Deprecated
@Override
public
final
boolean
quit
()
{
throw
new
UnsupportedOperationException
();
}
public
void
update
()
{
lastTime
=
System
.
currentTimeMillis
();
/**
* synchronize the state of the thread with ServerConfig.
*/
@DebugLog
/* package */
Single
<
Boolean
>
keepAlive
()
{
return
checkIfConnectionAlive
()
.
flatMap
(
alive
->
alive
?
Single
.
just
(
true
)
:
connectWithExponentialBackoff
());
}
}
private
final
KeepAliveTimer
keepAliveTimer
=
new
KeepAliveTimer
(
20000
);
private
RocketChatWebSocketThread
(
Context
appContext
,
String
hostname
)
{
super
(
"RC_thread_"
+
hostname
);
this
.
appContext
=
appContext
;
this
.
hostname
=
hostname
;
this
.
realmHelper
=
RealmStore
.
getOrCreate
(
hostname
);
this
.
connectivityManager
=
ConnectivityManager
.
getInstanceForInternal
(
appContext
);
}
/**
* build new Thread.
*/
@DebugLog
public
static
Single
<
RocketChatWebSocketThread
>
getStarted
(
Context
appContext
,
String
hostname
)
{
return
Single
.<
RocketChatWebSocketThread
>
fromEmitter
(
objectSingleEmitter
->
{
new
RocketChatWebSocketThread
(
appContext
,
hostname
)
{
@Override
protected
void
onLooperPrepared
()
{
try
{
super
.
onLooperPrepared
();
objectSingleEmitter
.
onSuccess
(
this
);
}
catch
(
Exception
exception
)
{
objectSingleEmitter
.
onError
(
exception
);
}
@DebugLog
private
Single
<
Boolean
>
checkIfConnectionAlive
()
{
if
(
DDPClient
.
get
()
==
null
)
{
return
Single
.
just
(
false
);
}
}.
start
();
}).
flatMap
(
webSocket
->
webSocket
.
connect
().
map
(
_val
->
webSocket
));
}
@Override
protected
void
onLooperPrepared
()
{
super
.
onLooperPrepared
();
forceInvalidateTokens
();
}
private
void
forceInvalidateTokens
()
{
realmHelper
.
executeTransaction
(
realm
->
{
RealmSession
session
=
RealmSession
.
queryDefaultSession
(
realm
).
findFirst
();
if
(
session
!=
null
&&
!
TextUtils
.
isEmpty
(
session
.
getToken
())
&&
(
session
.
isTokenVerified
()
||
!
TextUtils
.
isEmpty
(
session
.
getError
())))
{
session
.
setTokenVerified
(
false
);
session
.
setError
(
null
);
}
return
null
;
}).
continueWith
(
new
LogIfError
());
}
/**
* terminate WebSocket thread.
*/
@DebugLog
public
Single
<
Boolean
>
terminate
()
{
if
(
isAlive
())
{
return
Single
.
fromEmitter
(
emitter
->
{
new
Handler
(
getLooper
()).
post
(()
->
{
RCLog
.
d
(
"thread %s: terminated()"
,
Thread
.
currentThread
().
getId
());
unregisterListenersAndClose
();
connectivityManager
.
notifyConnectionLost
(
hostname
,
ConnectivityManagerInternal
.
REASON_CLOSED_BY_USER
);
RocketChatWebSocketThread
.
super
.
quit
();
emitter
.
onSuccess
(
true
);
return
Single
.
create
(
emitter
->
{
new
Thread
()
{
@Override
public
void
run
()
{
DDPClient
.
get
().
ping
().
continueWith
(
task
->
{
if
(
task
.
isFaulted
())
{
Exception
error
=
task
.
getError
();
RCLog
.
e
(
error
);
connectivityManager
.
notifyConnectionLost
(
hostname
,
DDPClient
.
REASON_CLOSED_BY_USER
);
emitter
.
onSuccess
(
false
);
}
else
{
emitter
.
onSuccess
(
true
);
}
return
null
;
});
}
}.
start
();
});
});
}
else
{
connectivityManager
.
notifyConnectionLost
(
hostname
,
ConnectivityManagerInternal
.
REASON_NETWORK_ERROR
);
super
.
quit
();
return
Single
.
just
(
true
);
}
}
/**
* THIS METHOD THROWS EXCEPTION!! Use terminate() instead!!
*/
@Deprecated
@Override
public
final
boolean
quit
()
{
throw
new
UnsupportedOperationException
();
}
/**
* synchronize the state of the thread with ServerConfig.
*/
@DebugLog
public
Single
<
Boolean
>
keepAlive
()
{
return
checkIfConnectionAlive
()
.
flatMap
(
alive
->
alive
?
Single
.
just
(
true
)
:
connectWithExponentialBackoff
());
}
@DebugLog
private
Single
<
Boolean
>
checkIfConnectionAlive
()
{
if
(
ddpClient
==
null
)
{
return
Single
.
just
(
false
);
}
if
(!
keepAliveTimer
.
shouldCheckPrecisely
())
{
return
Single
.
just
(
true
);
@DebugLog
private
Flowable
<
Boolean
>
heartbeat
(
long
interval
)
{
return
Flowable
.
interval
(
interval
,
TimeUnit
.
MILLISECONDS
)
.
onBackpressureDrop
()
.
flatMap
(
tick
->
DDPClient
.
get
().
doPing
().
toFlowable
())
.
map
(
callback
->
{
if
(
callback
instanceof
DDPClientCallback
.
Ping
)
{
return
true
;
}
// ideally we should never get here. We should always receive a DDPClientCallback.Ping
// because we just received a pong. But maybe we received a pong from an unmatched
// ping id which we should ignore. In this case or any other random error, log and
// send false downstream
RCLog
.
d
(
"heartbeat pong < %s"
,
callback
.
toString
());
return
false
;
});
}
keepAliveTimer
.
update
();
return
Single
.
fromEmitter
(
emitter
->
{
new
Thread
()
{
@Override
public
void
run
()
{
ddpClient
.
ping
().
continueWith
(
task
->
{
if
(
task
.
isFaulted
())
{
Exception
error
=
task
.
getError
();
RCLog
.
e
(
error
);
emitter
.
onError
(
error
);
}
else
{
keepAliveTimer
.
update
();
emitter
.
onSuccess
(
true
);
private
Single
<
Boolean
>
connectDDPClient
()
{
return
Single
.
create
(
emitter
->
{
ServerInfo
info
=
connectivityManager
.
getServerInfoForHost
(
hostname
);
if
(
info
==
null
)
{
emitter
.
onSuccess
(
false
);
return
;
}
return
null
;
});
}
}.
start
();
});
}
@DebugLog
private
Flowable
<
Boolean
>
heartbeat
(
long
interval
)
{
return
Flowable
.
interval
(
interval
,
TimeUnit
.
MILLISECONDS
)
.
onBackpressureDrop
()
.
flatMap
(
tick
->
ddpClient
.
doPing
().
toFlowable
())
.
map
(
callback
->
{
if
(
callback
instanceof
DDPClientCallback
.
Ping
)
{
return
true
;
}
// ideally we should never get here. We should always receive a DDPClientCallback.Ping
// because we just received a pong. But maybe we received a pong from an unmatched
// ping id which we should ignore. In this case or any other random error, log and
// send false downstream
RCLog
.
d
(
"heartbeat pong < %s"
,
callback
.
toString
());
return
false
;
});
}
private
Single
<
Boolean
>
prepareDDPClient
()
{
// TODO: temporarily replaced checkIfConnectionAlive() call for this single checking if ddpClient is
// null or not. In case it is, build a new client, otherwise just keep connecting with existing one.
return
Single
.
just
(
ddpClient
!=
null
)
.
doOnSuccess
(
alive
->
{
if
(!
alive
)
{
RCLog
.
d
(
"DDPClient#build"
);
ddpClient
=
DDPClientWrapper
.
create
(
hostname
);
}
RCLog
.
d
(
"DDPClient#connect"
);
connectivityManager
.
notifyConnecting
(
hostname
);
DDPClient
.
get
().
connect
(
hostname
,
info
.
getSession
(),
info
.
isSecure
())
.
onSuccessTask
(
task
->
{
final
String
newSession
=
task
.
getResult
().
session
;
connectivityManager
.
notifyConnectionEstablished
(
hostname
,
newSession
);
// handling WebSocket#onClose() callback.
task
.
getResult
().
client
.
getOnCloseCallback
().
onSuccess
(
_task
->
{
RxWebSocketCallback
.
Close
result
=
_task
.
getResult
();
if
(
result
.
code
==
DDPClient
.
REASON_NETWORK_ERROR
)
{
reconnect
();
}
return
null
;
});
return
realmHelper
.
executeTransaction
(
realm
->
{
RealmSession
sessionObj
=
RealmSession
.
queryDefaultSession
(
realm
).
findFirst
();
if
(
sessionObj
==
null
)
{
realm
.
createOrUpdateObjectFromJson
(
RealmSession
.
class
,
new
JSONObject
().
put
(
RealmSession
.
ID
,
RealmSession
.
DEFAULT_ID
));
}
else
{
// invalidate login token.
if
(!
TextUtils
.
isEmpty
(
sessionObj
.
getToken
())
&&
sessionObj
.
isTokenVerified
())
{
sessionObj
.
setTokenVerified
(
false
);
sessionObj
.
setError
(
null
);
}
}
return
null
;
});
})
.
continueWith
(
task
->
{
if
(
task
.
isFaulted
())
{
emitter
.
onError
(
task
.
getError
());
}
else
{
emitter
.
onSuccess
(
true
);
}
return
null
;
});
});
}
private
Single
<
Boolean
>
connectDDPClient
()
{
return
prepareDDPClient
()
.
flatMap
(
_val
->
Single
.
fromEmitter
(
emitter
->
{
ServerInfo
info
=
connectivityManager
.
getServerInfoForHost
(
hostname
);
if
(
info
==
null
)
{
emitter
.
onSuccess
(
false
);
}
private
void
reconnect
()
{
// if we are already trying to reconnect then return.
if
(
reconnectDisposable
.
size
()
>
0
)
{
return
;
}
RCLog
.
d
(
"DDPClient#connect"
);
ddpClient
.
connect
(
info
.
getSession
(),
info
.
isSecure
())
.
onSuccessTask
(
task
->
{
final
String
newSession
=
task
.
getResult
().
session
;
connectivityManager
.
notifyConnectionEstablished
(
hostname
,
newSession
);
// handling WebSocket#onClose() callback.
task
.
getResult
().
client
.
getOnCloseCallback
().
onSuccess
(
_task
->
{
reconnect
();
return
null
;
});
}
forceInvalidateTokens
();
reconnectDisposable
.
add
(
connectWithExponentialBackoff
()
.
subscribe
(
connected
->
{
if
(!
connected
)
{
connectivityManager
.
notifyConnectionLost
(
hostname
,
DDPClient
.
REASON_NETWORK_ERROR
);
}
reconnectDisposable
.
clear
();
},
error
->
{
connectivityManager
.
notifyConnectionLost
(
hostname
,
DDPClient
.
REASON_NETWORK_ERROR
);
logErrorAndUnsubscribe
(
reconnectDisposable
,
error
);
}
)
);
}
return
realmHelper
.
executeTransaction
(
realm
->
{
RealmSession
sessionObj
=
RealmSession
.
queryDefaultSession
(
realm
).
findFirst
();
if
(
sessionObj
==
null
)
{
realm
.
createOrUpdateObjectFromJson
(
RealmSession
.
class
,
new
JSONObject
().
put
(
RealmSession
.
ID
,
RealmSession
.
DEFAULT_ID
));
}
else
{
// invalidate login token.
if
(!
TextUtils
.
isEmpty
(
sessionObj
.
getToken
())
&&
sessionObj
.
isTokenVerified
())
{
sessionObj
.
setTokenVerified
(
false
);
sessionObj
.
setError
(
null
);
}
private
void
logErrorAndUnsubscribe
(
CompositeDisposable
disposables
,
Throwable
err
)
{
RCLog
.
e
(
err
);
disposables
.
clear
();
}
}
return
null
;
});
})
.
continueWith
(
task
->
{
if
(
task
.
isFaulted
())
{
emitter
.
onError
(
task
.
getError
());
}
else
{
emitter
.
onSuccess
(
true
);
}
return
null
;
});
}));
}
private
void
reconnect
()
{
// if we are already trying to reconnect then return.
if
(
reconnectSubscription
.
hasSubscriptions
())
{
return
;
private
Single
<
Boolean
>
connectWithExponentialBackoff
()
{
return
connect
()
.
retryWhen
(
RxHelper
.
exponentialBackoff
(
1
,
250
,
TimeUnit
.
MILLISECONDS
))
.
onErrorResumeNext
(
Single
.
just
(
false
));
}
ddpClient
.
close
();
forceInvalidateTokens
();
connectivityManager
.
notifyConnecting
(
hostname
);
// Needed to use subscriptions because of legacy code.
// TODO: Should update to RxJava 2
reconnectSubscription
.
add
(
connectWithExponentialBackoff
()
.
subscribe
(
connected
->
{
if
(!
connected
)
{
connectivityManager
.
notifyConnecting
(
hostname
);
}
reconnectSubscription
.
clear
();
},
err
->
logErrorAndUnsubscribe
(
reconnectSubscription
,
err
)
)
);
}
private
void
logErrorAndUnsubscribe
(
CompositeSubscription
subscriptions
,
Throwable
err
)
{
RCLog
.
e
(
err
);
subscriptions
.
clear
();
}
private
Single
<
Boolean
>
connectWithExponentialBackoff
()
{
return
connect
().
retryWhen
(
RxHelper
.
exponentialBackoff
(
Integer
.
MAX_VALUE
,
500
,
TimeUnit
.
MILLISECONDS
));
}
@DebugLog
private
Single
<
Boolean
>
connect
()
{
return
connectDDPClient
()
.
flatMap
(
_val
->
Single
.
fromEmitter
(
emitter
->
{
fetchPublicSettings
();
fetchPermissions
();
registerListeners
();
emitter
.
onSuccess
(
true
);
}));
}
private
Task
<
Void
>
fetchPublicSettings
()
{
return
new
MethodCallHelper
(
realmHelper
,
ddpClientRef
).
getPublicSettings
();
}
private
Task
<
Void
>
fetchPermissions
()
{
return
new
MethodCallHelper
(
realmHelper
,
ddpClientRef
).
getPermissions
();
}
@DebugLog
private
void
registerListeners
()
{
if
(!
Thread
.
currentThread
().
getName
().
equals
(
"RC_thread_"
+
hostname
))
{
// execute in Looper.
new
Handler
(
getLooper
()).
post
(
this
::
registerListeners
);
return
;
@DebugLog
private
Single
<
Boolean
>
connect
()
{
return
connectDDPClient
()
.
flatMap
(
_val
->
Single
.
create
(
emitter
->
{
fetchPublicSettings
();
fetchPermissions
();
registerListeners
();
emitter
.
onSuccess
(
true
);
}));
}
if
(
listenersRegistered
)
{
unregisterListeners
(
);
private
Task
<
Void
>
fetchPublicSettings
(
)
{
return
new
MethodCallHelper
(
appContext
,
realmHelper
).
getPublicSettings
(
hostname
);
}
List
<
RealmSession
>
sessions
=
realmHelper
.
executeTransactionForReadResults
(
realm
->
realm
.
where
(
RealmSession
.
class
)
.
isNotNull
(
RealmSession
.
TOKEN
)
.
equalTo
(
RealmSession
.
TOKEN_VERIFIED
,
false
)
.
isNull
(
RealmSession
.
ERROR
)
.
findAll
());
if
(
sessions
!=
null
&&
sessions
.
size
()
>
0
)
{
// if we have a session try to resume it. At this point we're probably recovering from
// a disconnection state
final
CompositeSubscription
subscriptions
=
new
CompositeSubscription
();
MethodCallHelper
methodCall
=
new
MethodCallHelper
(
realmHelper
,
ddpClientRef
);
subscriptions
.
add
(
Completable
.
defer
(()
->
{
Task
<
Void
>
result
=
methodCall
.
loginWithToken
(
sessions
.
get
(
0
).
getToken
());
if
(
result
.
isFaulted
())
{
return
Completable
.
error
(
result
.
getError
());
}
else
{
return
Completable
.
complete
();
}
}).
retryWhen
(
RxHelper
.
exponentialBackoff
(
Integer
.
MAX_VALUE
,
500
,
TimeUnit
.
MILLISECONDS
))
.
subscribe
(
()
->
{
createObserversAndRegister
();
subscriptions
.
clear
();
},
error
->
logErrorAndUnsubscribe
(
subscriptions
,
error
)
)
);
}
else
{
// if we don't have any session then just build the observers and register normally
createObserversAndRegister
();
private
Task
<
Void
>
fetchPermissions
()
{
return
new
MethodCallHelper
(
realmHelper
).
getPermissions
();
}
}
@DebugLog
private
void
createObserversAndRegister
()
{
for
(
Class
clazz
:
REGISTERABLE_CLASSES
)
{
try
{
Constructor
ctor
=
clazz
.
getConstructor
(
Context
.
class
,
String
.
class
,
RealmHelper
.
class
,
DDPClientRef
.
class
);
Object
obj
=
ctor
.
newInstance
(
appContext
,
hostname
,
realmHelper
,
ddpClientRef
);
if
(
obj
instanceof
Registrable
)
{
Registrable
registrable
=
(
Registrable
)
obj
;
registrable
.
register
();
listeners
.
add
(
registrable
);
@DebugLog
private
void
registerListeners
()
{
if
(!
Thread
.
currentThread
().
getName
().
equals
(
"RC_thread_"
+
hostname
))
{
// execute in Looper.
new
Handler
(
getLooper
()).
post
(
this
::
registerListeners
);
return
;
}
if
(
listenersRegistered
)
{
unregisterListeners
();
}
List
<
RealmSession
>
sessions
=
realmHelper
.
executeTransactionForReadResults
(
realm
->
realm
.
where
(
RealmSession
.
class
)
.
isNotNull
(
RealmSession
.
TOKEN
)
.
equalTo
(
RealmSession
.
TOKEN_VERIFIED
,
false
)
.
isNull
(
RealmSession
.
ERROR
)
.
findAll
());
if
(
sessions
!=
null
&&
sessions
.
size
()
>
0
)
{
// if we have a session try to resume it. At this point we're probably recovering from
// a disconnection state
final
CompositeDisposable
disposables
=
new
CompositeDisposable
();
MethodCallHelper
methodCall
=
new
MethodCallHelper
(
realmHelper
);
disposables
.
add
(
Completable
.
defer
(()
->
{
Task
<
Void
>
result
=
methodCall
.
loginWithToken
(
sessions
.
get
(
0
).
getToken
());
if
(
result
.
isFaulted
())
{
return
Completable
.
error
(
result
.
getError
());
}
else
{
return
Completable
.
complete
();
}
}).
retryWhen
(
RxHelper
.
exponentialBackoff
(
3
,
500
,
TimeUnit
.
MILLISECONDS
))
.
subscribe
(
()
->
{
createObserversAndRegister
();
disposables
.
clear
();
},
error
->
logErrorAndUnsubscribe
(
disposables
,
error
)
)
);
}
else
{
// if we don't have any session then just build the observers and register normally
createObserversAndRegister
();
}
}
catch
(
Exception
exception
)
{
RCLog
.
w
(
exception
,
"Failed to register listeners!!"
);
}
}
listenersRegistered
=
true
;
startHeartBeat
();
}
private
void
startHeartBeat
()
{
hearbeatDisposable
.
clear
();
hearbeatDisposable
.
add
(
heartbeat
(
HEARTBEAT_PERIOD_MS
)
.
subscribe
(
ponged
->
{
if
(!
ponged
)
{
RCLog
.
d
(
"Pong received but didn't match ping id"
);
}
},
error
->
{
RCLog
.
e
(
error
);
// Stop pinging
hearbeatDisposable
.
clear
();
if
(
error
instanceof
DDPClientCallback
.
Closed
)
{
RCLog
.
d
(
"Hearbeat failure: retrying connection..."
);
reconnect
();
}
}
)
);
}
@DebugLog
private
void
unregisterListenersAndClose
()
{
unregisterListeners
();
if
(
ddpClient
!=
null
)
{
ddpClient
.
close
();
ddpClient
=
null
;
@DebugLog
private
void
createObserversAndRegister
()
{
for
(
Class
clazz
:
REGISTERABLE_CLASSES
)
{
try
{
Constructor
ctor
=
clazz
.
getConstructor
(
Context
.
class
,
String
.
class
,
RealmHelper
.
class
);
Object
obj
=
ctor
.
newInstance
(
appContext
,
hostname
,
realmHelper
);
if
(
obj
instanceof
Registrable
)
{
Registrable
registrable
=
(
Registrable
)
obj
;
registrable
.
register
();
listeners
.
add
(
registrable
);
}
}
catch
(
Exception
exception
)
{
RCLog
.
w
(
exception
,
"Failed to register listeners!!"
);
}
}
listenersRegistered
=
true
;
startHeartBeat
();
}
}
@DebugLog
private
void
unregisterListeners
()
{
Iterator
<
Registrable
>
iterator
=
listeners
.
iterator
();
while
(
iterator
.
hasNext
())
{
Registrable
registrable
=
iterator
.
next
();
registrable
.
unregister
();
iterator
.
remove
();
private
void
startHeartBeat
()
{
heartbeatDisposable
.
clear
();
heartbeatDisposable
.
add
(
heartbeat
(
HEARTBEAT_PERIOD_MS
)
.
subscribe
(
ponged
->
{
if
(!
ponged
)
{
RCLog
.
d
(
"Pong received but didn't match ping id"
);
}
},
error
->
{
RCLog
.
e
(
error
);
// Stop pinging
heartbeatDisposable
.
clear
();
if
(
error
instanceof
DDPClientCallback
.
Closed
||
error
instanceof
TimeoutException
)
{
RCLog
.
d
(
"Hearbeat failure: retrying connection..."
);
reconnect
();
}
}
)
);
}
@DebugLog
private
void
unregisterListenersAndClose
()
{
unregisterListeners
();
DDPClient
.
get
().
close
();
}
@DebugLog
private
void
unregisterListeners
()
{
Iterator
<
Registrable
>
iterator
=
listeners
.
iterator
();
while
(
iterator
.
hasNext
())
{
Registrable
registrable
=
iterator
.
next
();
registrable
.
unregister
();
iterator
.
remove
();
}
heartbeatDisposable
.
clear
();
listenersRegistered
=
false
;
}
hearbeatDisposable
.
clear
();
listenersRegistered
=
false
;
}
}
app/src/main/java/chat/rocket/android/service/ServerConnectivity.java
View file @
5bbd3f7f
...
...
@@ -4,17 +4,43 @@ package chat.rocket.android.service;
* pair with server's hostname and its connectivity state.
*/
public
class
ServerConnectivity
{
public
static
final
int
STATE_CONNECTED
=
1
;
public
static
final
int
STATE_DISCONNECTED
=
2
;
public
static
final
int
STATE_CONNECTING
=
3
;
/*package*/
static
final
int
STATE_DISCONNECTING
=
4
;
public
static
final
ServerConnectivity
CONNECTED
=
new
ServerConnectivity
(
null
,
STATE_CONNECTED
);
public
final
String
hostname
;
public
final
int
state
;
public
final
int
code
;
ServerConnectivity
(
String
hostname
,
int
state
)
{
this
.
hostname
=
hostname
;
this
.
state
=
state
;
this
.
code
=
-
1
;
}
public
ServerConnectivity
(
String
hostname
,
int
stat
e
)
{
ServerConnectivity
(
String
hostname
,
int
state
,
int
cod
e
)
{
this
.
hostname
=
hostname
;
this
.
state
=
state
;
this
.
code
=
code
;
}
@Override
public
boolean
equals
(
Object
o
)
{
if
(
this
==
o
)
return
true
;
if
(
o
==
null
||
getClass
()
!=
o
.
getClass
())
return
false
;
ServerConnectivity
that
=
(
ServerConnectivity
)
o
;
return
state
==
that
.
state
;
}
@Override
public
int
hashCode
()
{
return
state
;
}
/**
...
...
app/src/main/java/chat/rocket/android/service/ddp/AbstractDDPDocEventSubscriber.java
View file @
5bbd3f7f
...
...
@@ -3,38 +3,37 @@ package chat.rocket.android.service.ddp;
import
android.content.Context
;
import
android.text.TextUtils
;
import
chat.rocket.persistence.realm.models.ddp.RealmUser
;
import
io.reactivex.disposables.Disposable
;
import
io.realm.Realm
;
import
io.realm.RealmObject
;
import
org.json.JSONArray
;
import
org.json.JSONException
;
import
org.json.JSONObject
;
import
java.util.Iterator
;
import
chat.rocket.android.helper.LogIfError
;
import
chat.rocket.android.log.RCLog
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.android.service.DDPClientRef
;
import
chat.rocket.android.service.Registrable
;
import
chat.rocket.android_ddp.DDPClient
;
import
chat.rocket.android_ddp.DDPSubscription
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.persistence.realm.models.ddp.RealmUser
;
import
io.reactivex.disposables.Disposable
;
import
io.realm.Realm
;
import
io.realm.RealmObject
;
import
io.realm.RealmResults
;
public
abstract
class
AbstractDDPDocEventSubscriber
implements
Registrable
{
protected
final
Context
context
;
protected
final
String
hostname
;
protected
final
RealmHelper
realmHelper
;
protected
final
DDPClientRef
ddpClientRef
;
private
boolean
isUnsubscribed
;
private
String
subscriptionId
;
private
Disposable
rxSubscription
;
protected
AbstractDDPDocEventSubscriber
(
Context
context
,
String
hostname
,
RealmHelper
realmHelper
,
DDPClientRef
ddpClientRef
)
{
RealmHelper
realmHelper
)
{
this
.
context
=
context
;
this
.
hostname
=
hostname
;
this
.
realmHelper
=
realmHelper
;
this
.
ddpClientRef
=
ddpClientRef
;
}
protected
abstract
String
getSubscriptionName
();
...
...
@@ -69,9 +68,9 @@ public abstract class AbstractDDPDocEventSubscriber implements Registrable {
// just ignore.
}
ddpClientRef
.
get
().
subscribe
(
getSubscriptionName
(),
params
).
onSuccess
(
task
->
{
DDPClient
.
get
().
subscribe
(
getSubscriptionName
(),
params
).
onSuccess
(
task
->
{
if
(
isUnsubscribed
)
{
ddpClientRef
.
get
().
unsubscribe
(
task
.
getResult
().
id
).
continueWith
(
new
LogIfError
());
DDPClient
.
get
().
unsubscribe
(
task
.
getResult
().
id
).
continueWith
(
new
LogIfError
());
}
else
{
subscriptionId
=
task
.
getResult
().
id
;
}
...
...
@@ -98,7 +97,7 @@ public abstract class AbstractDDPDocEventSubscriber implements Registrable {
}
protected
Disposable
subscribe
()
{
return
ddpClientRef
.
get
().
getSubscriptionCallback
()
return
DDPClient
.
get
().
getSubscriptionCallback
()
.
filter
(
event
->
event
instanceof
DDPSubscription
.
DocEvent
)
.
cast
(
DDPSubscription
.
DocEvent
.
class
)
.
filter
(
event
->
isTarget
(
event
.
collection
))
...
...
@@ -197,8 +196,8 @@ public abstract class AbstractDDPDocEventSubscriber implements Registrable {
if
(
rxSubscription
!=
null
)
{
rxSubscription
.
dispose
();
}
if
(!
TextUtils
.
isEmpty
(
subscriptionId
)
&&
ddpClientRef
.
get
()
!=
null
)
{
ddpClientRef
.
get
().
unsubscribe
(
subscriptionId
).
continueWith
(
new
LogIfError
());
if
(!
TextUtils
.
isEmpty
(
subscriptionId
)
&&
DDPClient
.
get
()
!=
null
)
{
DDPClient
.
get
().
unsubscribe
(
subscriptionId
).
continueWith
(
new
LogIfError
());
}
}
}
app/src/main/java/chat/rocket/android/service/ddp/base/AbstractBaseSubscriber.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
service
.
ddp
.
base
;
import
android.content.Context
;
import
org.json.JSONArray
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.android.service.DDPClientRef
;
import
chat.rocket.android.service.ddp.AbstractDDPDocEventSubscriber
;
import
chat.rocket.persistence.realm.RealmHelper
;
abstract
class
AbstractBaseSubscriber
extends
AbstractDDPDocEventSubscriber
{
protected
AbstractBaseSubscriber
(
Context
context
,
String
hostname
,
RealmHelper
realmHelper
,
DDPClientRef
ddpClientRef
)
{
super
(
context
,
hostname
,
realmHelper
,
ddpClientRef
);
protected
AbstractBaseSubscriber
(
Context
context
,
String
hostname
,
RealmHelper
realmHelper
)
{
super
(
context
,
hostname
,
realmHelper
);
}
@Override
...
...
app/src/main/java/chat/rocket/android/service/ddp/base/ActiveUsersSubscriber.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
service
.
ddp
.
base
;
import
android.content.Context
;
import
io.realm.RealmObject
;
import
org.json.JSONException
;
import
org.json.JSONObject
;
import
chat.rocket.persistence.realm.models.ddp.RealmUser
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.android.service.DDPClientRef
;
import
chat.rocket.persistence.realm.models.ddp.RealmUser
;
import
io.realm.RealmObject
;
/**
* "activeUsers" subscriber.
*/
public
class
ActiveUsersSubscriber
extends
AbstractBaseSubscriber
{
public
ActiveUsersSubscriber
(
Context
context
,
String
hostname
,
RealmHelper
realmHelper
,
DDPClientRef
ddpClientRef
)
{
super
(
context
,
hostname
,
realmHelper
,
ddpClientRef
);
public
ActiveUsersSubscriber
(
Context
context
,
String
hostname
,
RealmHelper
realmHelper
)
{
super
(
context
,
hostname
,
realmHelper
);
}
@Override
...
...
app/src/main/java/chat/rocket/android/service/ddp/base/LoginServiceConfigurationSubscriber.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
service
.
ddp
.
base
;
import
android.content.Context
;
import
io.realm.RealmObject
;
import
chat.rocket.persistence.realm.models.ddp.RealmMeteorLoginServiceConfiguration
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.android.service.DDPClientRef
;
import
chat.rocket.persistence.realm.models.ddp.RealmMeteorLoginServiceConfiguration
;
import
io.realm.RealmObject
;
/**
* meteor.loginServiceConfiguration subscriber
*/
public
class
LoginServiceConfigurationSubscriber
extends
AbstractBaseSubscriber
{
public
LoginServiceConfigurationSubscriber
(
Context
context
,
String
hostname
,
RealmHelper
realmHelper
,
DDPClientRef
ddpClientRef
)
{
super
(
context
,
hostname
,
realmHelper
,
ddpClientRef
);
RealmHelper
realmHelper
)
{
super
(
context
,
hostname
,
realmHelper
);
}
@Override
...
...
app/src/main/java/chat/rocket/android/service/ddp/base/UserDataSubscriber.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
service
.
ddp
.
base
;
import
android.content.Context
;
import
io.realm.RealmObject
;
import
org.json.JSONException
;
import
org.json.JSONObject
;
import
chat.rocket.persistence.realm.models.ddp.RealmUser
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.android.service.DDPClientRef
;
import
chat.rocket.persistence.realm.models.ddp.RealmUser
;
import
io.realm.RealmObject
;
/**
* "userData" subscriber.
*/
public
class
UserDataSubscriber
extends
AbstractBaseSubscriber
{
public
UserDataSubscriber
(
Context
context
,
String
hostname
,
RealmHelper
realmHelper
,
DDPClientRef
ddpClientRef
)
{
super
(
context
,
hostname
,
realmHelper
,
ddpClientRef
);
public
UserDataSubscriber
(
Context
context
,
String
hostname
,
RealmHelper
realmHelper
)
{
super
(
context
,
hostname
,
realmHelper
);
}
@Override
...
...
app/src/main/java/chat/rocket/android/service/ddp/stream/AbstractStreamNotifyEventSubscriber.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
service
.
ddp
.
stream
;
import
android.content.Context
;
import
org.json.JSONArray
;
import
org.json.JSONException
;
import
org.json.JSONObject
;
import
chat.rocket.android.helper.LogIfError
;
import
chat.rocket.android.log.RCLog
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.android.service.DDPClientRef
;
import
chat.rocket.android.service.ddp.AbstractDDPDocEventSubscriber
;
import
chat.rocket.android_ddp.DDPSubscription
;
import
chat.rocket.persistence.realm.RealmHelper
;
abstract
class
AbstractStreamNotifyEventSubscriber
extends
AbstractDDPDocEventSubscriber
{
protected
AbstractStreamNotifyEventSubscriber
(
Context
context
,
String
hostname
,
RealmHelper
realmHelper
,
DDPClientRef
ddpClientRef
)
{
super
(
context
,
hostname
,
realmHelper
,
ddpClientRef
);
RealmHelper
realmHelper
)
{
super
(
context
,
hostname
,
realmHelper
);
}
@Override
...
...
app/src/main/java/chat/rocket/android/service/ddp/stream/AbstractStreamNotifyUserEventSubscriber.java
View file @
5bbd3f7f
...
...
@@ -3,15 +3,13 @@ package chat.rocket.android.service.ddp.stream;
import
android.content.Context
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.android.service.DDPClientRef
;
abstract
class
AbstractStreamNotifyUserEventSubscriber
extends
AbstractStreamNotifyEventSubscriber
{
protected
final
String
userId
;
protected
AbstractStreamNotifyUserEventSubscriber
(
Context
context
,
String
hostname
,
RealmHelper
realmHelper
,
DDPClientRef
ddpClientRef
,
String
userId
)
{
super
(
context
,
hostname
,
realmHelper
,
ddpClientRef
);
RealmHelper
realmHelper
,
String
userId
)
{
super
(
context
,
hostname
,
realmHelper
);
this
.
userId
=
userId
;
}
...
...
app/src/main/java/chat/rocket/android/service/ddp/stream/StreamNotifyUserSubscriptionsChanged.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
service
.
ddp
.
stream
;
import
android.content.Context
;
import
io.realm.RealmObject
;
import
org.json.JSONException
;
import
org.json.JSONObject
;
import
chat.rocket.persistence.realm.models.ddp.RealmRoom
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.android.service.DDPClientRef
;
import
chat.rocket.persistence.realm.models.ddp.RealmRoom
;
import
io.realm.RealmObject
;
public
class
StreamNotifyUserSubscriptionsChanged
extends
AbstractStreamNotifyUserEventSubscriber
{
public
StreamNotifyUserSubscriptionsChanged
(
Context
context
,
String
hostname
,
RealmHelper
realmHelper
,
DDPClientRef
ddpClientRef
,
RealmHelper
realmHelper
,
String
userId
)
{
super
(
context
,
hostname
,
realmHelper
,
ddpClientRef
,
userId
);
super
(
context
,
hostname
,
realmHelper
,
userId
);
}
@Override
...
...
app/src/main/java/chat/rocket/android/service/ddp/stream/StreamRoomMessage.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
service
.
ddp
.
stream
;
import
android.content.Context
;
import
io.realm.RealmObject
;
import
org.json.JSONException
;
import
org.json.JSONObject
;
import
chat.rocket.persistence.realm.models.ddp.RealmMessage
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.android.service.DDPClientRef
;
import
chat.rocket.persistence.realm.models.ddp.RealmMessage
;
import
io.realm.RealmObject
;
/**
* stream-room-message subscriber.
...
...
@@ -16,8 +16,8 @@ public class StreamRoomMessage extends AbstractStreamNotifyEventSubscriber {
private
String
roomId
;
public
StreamRoomMessage
(
Context
context
,
String
hostname
,
RealmHelper
realmHelper
,
DDPClientRef
ddpClientRef
,
String
roomId
)
{
super
(
context
,
hostname
,
realmHelper
,
ddpClientRef
);
RealmHelper
realmHelper
,
String
roomId
)
{
super
(
context
,
hostname
,
realmHelper
);
this
.
roomId
=
roomId
;
}
...
...
app/src/main/java/chat/rocket/android/service/internal/StreamRoomMessageManager.java
View file @
5bbd3f7f
...
...
@@ -5,10 +5,9 @@ import android.os.Handler;
import
android.os.Looper
;
import
chat.rocket.android.RocketChatCache
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.android.service.DDPClientRef
;
import
chat.rocket.android.service.Registrable
;
import
chat.rocket.android.service.ddp.stream.StreamRoomMessage
;
import
chat.rocket.persistence.realm.RealmHelper
;
/**
* wrapper for managing stream-notify-message depending on RocketChatCache.
...
...
@@ -17,18 +16,16 @@ public class StreamRoomMessageManager implements Registrable {
private
final
Context
context
;
private
final
String
hostname
;
private
final
RealmHelper
realmHelper
;
private
final
DDPClientRef
ddpClientRef
;
private
final
AbstractRocketChatCacheObserver
cacheObserver
;
private
final
Handler
handler
;
private
final
RocketChatCache
rocketChatCache
;
private
StreamRoomMessage
streamRoomMessage
;
public
StreamRoomMessageManager
(
Context
context
,
String
hostname
,
RealmHelper
realmHelper
,
DDPClientRef
ddpClientRef
)
{
RealmHelper
realmHelper
)
{
this
.
context
=
context
;
this
.
hostname
=
hostname
;
this
.
realmHelper
=
realmHelper
;
this
.
ddpClientRef
=
ddpClientRef
;
this
.
rocketChatCache
=
new
RocketChatCache
(
context
);
cacheObserver
=
new
AbstractRocketChatCacheObserver
(
context
,
realmHelper
)
{
...
...
@@ -43,7 +40,7 @@ public class StreamRoomMessageManager implements Registrable {
private
void
registerStreamNotifyMessage
(
String
roomId
)
{
handler
.
post
(()
->
{
streamRoomMessage
=
new
StreamRoomMessage
(
context
,
hostname
,
realmHelper
,
ddpClientRef
,
roomId
);
streamRoomMessage
=
new
StreamRoomMessage
(
context
,
hostname
,
realmHelper
,
roomId
);
streamRoomMessage
.
register
();
});
}
...
...
app/src/main/java/chat/rocket/android/service/observer/AbstractModelObserver.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
service
.
observer
;
import
android.content.Context
;
import
io.realm.RealmObject
;
import
chat.rocket.android.service.Registrable
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.persistence.realm.RealmListObserver
;
import
chat.rocket.android.service.DDPClientRef
;
import
chat.rocket.android.service.Registrable
;
import
io.realm.RealmObject
;
abstract
class
AbstractModelObserver
<
T
extends
RealmObject
>
implements
Registrable
,
RealmListObserver
.
Query
<
T
>,
RealmListObserver
.
OnUpdateListener
<
T
>
{
...
...
@@ -14,15 +13,13 @@ abstract class AbstractModelObserver<T extends RealmObject>
protected
final
Context
context
;
protected
final
String
hostname
;
protected
final
RealmHelper
realmHelper
;
protected
final
DDPClientRef
ddpClientRef
;
private
final
RealmListObserver
observer
;
protected
AbstractModelObserver
(
Context
context
,
String
hostname
,
RealmHelper
realmHelper
,
DDPClientRef
ddpClientRef
)
{
RealmHelper
realmHelper
)
{
this
.
context
=
context
;
this
.
hostname
=
hostname
;
this
.
realmHelper
=
realmHelper
;
this
.
ddpClientRef
=
ddpClientRef
;
observer
=
realmHelper
.
createListObserver
(
this
).
setOnUpdateListener
(
this
);
}
...
...
app/src/main/java/chat/rocket/android/service/observer/CurrentUserObserver.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
service
.
observer
;
import
android.content.Context
;
import
io.realm.Realm
;
import
io.realm.RealmResults
;
import
java.util.ArrayList
;
import
java.util.List
;
import
chat.rocket.android.api.MethodCallHelper
;
import
chat.rocket.android.helper.LogIfError
;
import
chat.rocket.persistence.realm.models.ddp.RealmUser
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.android.service.DDPClientRef
;
import
chat.rocket.android.service.Registrable
;
import
chat.rocket.android.service.ddp.stream.StreamNotifyUserSubscriptionsChanged
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.persistence.realm.models.ddp.RealmUser
;
import
hugo.weaving.DebugLog
;
import
io.realm.Realm
;
import
io.realm.RealmResults
;
/**
* observe the user with emails.
...
...
@@ -24,9 +24,9 @@ public class CurrentUserObserver extends AbstractModelObserver<RealmUser> {
private
ArrayList
<
Registrable
>
listeners
;
public
CurrentUserObserver
(
Context
context
,
String
hostname
,
RealmHelper
realmHelper
,
DDPClientRef
ddpClientRef
)
{
super
(
context
,
hostname
,
realmHelper
,
ddpClientRef
);
methodCall
=
new
MethodCallHelper
(
realmHelper
,
ddpClientRef
);
RealmHelper
realmHelper
)
{
super
(
context
,
hostname
,
realmHelper
);
methodCall
=
new
MethodCallHelper
(
realmHelper
);
currentUserExists
=
false
;
}
...
...
@@ -62,7 +62,7 @@ public class CurrentUserObserver extends AbstractModelObserver<RealmUser> {
methodCall
.
getRoomSubscriptions
().
onSuccess
(
task
->
{
if
(
listeners
!=
null
)
{
Registrable
listener
=
new
StreamNotifyUserSubscriptionsChanged
(
context
,
hostname
,
realmHelper
,
ddpClientRef
,
userId
);
context
,
hostname
,
realmHelper
,
userId
);
listener
.
register
();
listeners
.
add
(
listener
);
}
...
...
app/src/main/java/chat/rocket/android/service/observer/DeletedMessageObserver.java
0 → 100644
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
service
.
observer
;
import
android.content.Context
;
import
org.json.JSONObject
;
import
java.util.List
;
import
chat.rocket.android.api.MethodCallHelper
;
import
chat.rocket.android.helper.LogIfError
;
import
chat.rocket.android.log.RCLog
;
import
chat.rocket.core.SyncState
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.persistence.realm.models.ddp.RealmMessage
;
import
io.realm.Realm
;
import
io.realm.RealmResults
;
/**
* Observe messages for deletion.
*/
public
class
DeletedMessageObserver
extends
AbstractModelObserver
<
RealmMessage
>
{
private
final
MethodCallHelper
methodCall
;
public
DeletedMessageObserver
(
Context
context
,
String
hostname
,
RealmHelper
realmHelper
)
{
super
(
context
,
hostname
,
realmHelper
);
methodCall
=
new
MethodCallHelper
(
realmHelper
);
realmHelper
.
executeTransaction
(
realm
->
{
// resume pending operations.
RealmResults
<
RealmMessage
>
pendingMethodCalls
=
realm
.
where
(
RealmMessage
.
class
)
.
equalTo
(
RealmMessage
.
SYNC_STATE
,
SyncState
.
DELETING
)
.
findAll
();
for
(
RealmMessage
message
:
pendingMethodCalls
)
{
message
.
setSyncState
(
SyncState
.
DELETE_NOT_SYNCED
);
}
return
null
;
}).
continueWith
(
new
LogIfError
());
}
@Override
public
RealmResults
<
RealmMessage
>
queryItems
(
Realm
realm
)
{
return
realm
.
where
(
RealmMessage
.
class
)
.
equalTo
(
RealmMessage
.
SYNC_STATE
,
SyncState
.
DELETE_NOT_SYNCED
)
.
isNotNull
(
RealmMessage
.
ROOM_ID
)
.
findAll
();
}
@Override
public
void
onUpdateResults
(
List
<
RealmMessage
>
results
)
{
if
(
results
.
isEmpty
())
{
return
;
}
for
(
RealmMessage
message
:
results
)
{
final
String
messageId
=
message
.
getId
();
realmHelper
.
executeTransaction
(
realm
->
realm
.
createOrUpdateObjectFromJson
(
RealmMessage
.
class
,
new
JSONObject
()
.
put
(
RealmMessage
.
ID
,
messageId
)
.
put
(
RealmMessage
.
SYNC_STATE
,
SyncState
.
DELETING
)
)
).
onSuccessTask
(
task
->
methodCall
.
deleteMessage
(
messageId
)
).
continueWith
(
task
->
{
if
(
task
.
isFaulted
())
{
RCLog
.
w
(
task
.
getError
());
realmHelper
.
executeTransaction
(
realm
->
realm
.
createOrUpdateObjectFromJson
(
RealmMessage
.
class
,
new
JSONObject
()
.
put
(
RealmMessage
.
ID
,
messageId
)
.
put
(
RealmMessage
.
SYNC_STATE
,
SyncState
.
DELETE_FAILED
)));
}
else
{
realmHelper
.
executeTransaction
(
realm
->
realm
.
where
(
RealmMessage
.
class
)
.
equalTo
(
RealmMessage
.
ID
,
messageId
)
.
findAll
()
.
deleteAllFromRealm
()
);
}
return
null
;
});
}
}
}
app/src/main/java/chat/rocket/android/service/observer/FileUploadingToUrlObserver.java
View file @
5bbd3f7f
...
...
@@ -2,23 +2,24 @@ package chat.rocket.android.service.observer;
import
android.content.Context
;
import
android.net.Uri
;
import
chat.rocket.android.helper.OkHttpHelper
;
import
io.realm.Realm
;
import
io.realm.RealmResults
;
import
org.json.JSONArray
;
import
org.json.JSONObject
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.util.List
;
import
bolts.Task
;
import
chat.rocket.android.api.FileUploadingHelper
;
import
chat.rocket.android.helper.LogIfError
;
import
chat.rocket.android.helper.OkHttpHelper
;
import
chat.rocket.android.log.RCLog
;
import
chat.rocket.core.SyncState
;
import
chat.rocket.persistence.realm.models.internal.FileUploading
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.android.service.DDPClientRef
;
import
chat.rocket.persistence.realm.models.internal.FileUploading
;
import
io.realm.Realm
;
import
io.realm.RealmResults
;
import
okhttp3.MediaType
;
import
okhttp3.MultipartBody
;
import
okhttp3.Request
;
...
...
@@ -35,9 +36,9 @@ public class FileUploadingToUrlObserver extends AbstractModelObserver<FileUpload
private
FileUploadingHelper
methodCall
;
public
FileUploadingToUrlObserver
(
Context
context
,
String
hostname
,
RealmHelper
realmHelper
,
DDPClientRef
ddpClientRef
)
{
super
(
context
,
hostname
,
realmHelper
,
ddpClientRef
);
methodCall
=
new
FileUploadingHelper
(
realmHelper
,
ddpClientRef
);
RealmHelper
realmHelper
)
{
super
(
context
,
hostname
,
realmHelper
);
methodCall
=
new
FileUploadingHelper
(
realmHelper
);
realmHelper
.
executeTransaction
(
realm
->
{
// resume pending operations.
...
...
app/src/main/java/chat/rocket/android/service/observer/FileUploadingWithUfsObserver.java
View file @
5bbd3f7f
...
...
@@ -2,23 +2,24 @@ package chat.rocket.android.service.observer;
import
android.content.Context
;
import
android.net.Uri
;
import
chat.rocket.android.helper.OkHttpHelper
;
import
io.realm.Realm
;
import
io.realm.RealmResults
;
import
org.json.JSONObject
;
import
java.io.InputStream
;
import
java.util.List
;
import
bolts.Task
;
import
chat.rocket.android.api.FileUploadingHelper
;
import
chat.rocket.android.helper.LogIfError
;
import
chat.rocket.android.helper.OkHttpHelper
;
import
chat.rocket.android.log.RCLog
;
import
chat.rocket.core.SyncState
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.persistence.realm.models.ddp.RealmUser
;
import
chat.rocket.persistence.realm.models.internal.FileUploading
;
import
chat.rocket.persistence.realm.models.internal.RealmSession
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.android.service.DDPClientRef
;
import
io.realm.Realm
;
import
io.realm.RealmResults
;
import
okhttp3.MediaType
;
import
okhttp3.Request
;
import
okhttp3.RequestBody
;
...
...
@@ -31,9 +32,9 @@ public class FileUploadingWithUfsObserver extends AbstractModelObserver<FileUplo
private
FileUploadingHelper
methodCall
;
public
FileUploadingWithUfsObserver
(
Context
context
,
String
hostname
,
RealmHelper
realmHelper
,
DDPClientRef
ddpClientRef
)
{
super
(
context
,
hostname
,
realmHelper
,
ddpClientRef
);
methodCall
=
new
FileUploadingHelper
(
realmHelper
,
ddpClientRef
);
RealmHelper
realmHelper
)
{
super
(
context
,
hostname
,
realmHelper
);
methodCall
=
new
FileUploadingHelper
(
realmHelper
);
realmHelper
.
executeTransaction
(
realm
->
{
// resume pending operations.
...
...
app/src/main/java/chat/rocket/android/service/observer/GcmPushRegistrationObserver.java
View file @
5bbd3f7f
...
...
@@ -13,7 +13,6 @@ import chat.rocket.android.R;
import
chat.rocket.android.RocketChatCache
;
import
chat.rocket.android.api.RaixPushHelper
;
import
chat.rocket.android.helper.LogIfError
;
import
chat.rocket.android.service.DDPClientRef
;
import
chat.rocket.core.SyncState
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.persistence.realm.models.ddp.RealmUser
;
...
...
@@ -26,9 +25,8 @@ import io.realm.RealmResults;
*/
public
class
GcmPushRegistrationObserver
extends
AbstractModelObserver
<
GcmPushRegistration
>
{
public
GcmPushRegistrationObserver
(
Context
context
,
String
hostname
,
RealmHelper
realmHelper
,
DDPClientRef
ddpClientRef
)
{
super
(
context
,
hostname
,
realmHelper
,
ddpClientRef
);
RealmHelper
realmHelper
)
{
super
(
context
,
hostname
,
realmHelper
);
}
@Override
...
...
@@ -72,7 +70,7 @@ public class GcmPushRegistrationObserver extends AbstractModelObserver<GcmPushRe
final
String
userId
=
currentUser
!=
null
?
currentUser
.
getId
()
:
null
;
final
String
pushId
=
new
RocketChatCache
(
context
).
getOrCreatePushId
();
return
new
RaixPushHelper
(
realmHelper
,
ddpClientRef
)
return
new
RaixPushHelper
(
realmHelper
)
.
pushUpdate
(
pushId
,
gcmToken
,
userId
);
}
...
...
app/src/main/java/chat/rocket/android/service/observer/GetUsersOfRoomsProcedureObserver.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
service
.
observer
;
import
android.content.Context
;
import
io.realm.Realm
;
import
io.realm.RealmResults
;
import
org.json.JSONObject
;
import
java.util.List
;
import
bolts.Task
;
import
chat.rocket.android.api.MethodCallHelper
;
import
chat.rocket.android.log.RCLog
;
import
chat.rocket.core.SyncState
;
import
chat.rocket.persistence.realm.models.internal.GetUsersOfRoomsProcedure
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.android.service.DDPClientRef
;
import
chat.rocket.persistence.realm.models.internal.GetUsersOfRoomsProcedure
;
import
io.realm.Realm
;
import
io.realm.RealmResults
;
/**
* Model observer for executing getUsersOfRooms.
...
...
@@ -23,9 +24,9 @@ public class GetUsersOfRoomsProcedureObserver
private
final
MethodCallHelper
methodCall
;
public
GetUsersOfRoomsProcedureObserver
(
Context
context
,
String
hostname
,
RealmHelper
realmHelper
,
DDPClientRef
ddpClientRef
)
{
super
(
context
,
hostname
,
realmHelper
,
ddpClientRef
);
methodCall
=
new
MethodCallHelper
(
realmHelper
,
ddpClientRef
);
RealmHelper
realmHelper
)
{
super
(
context
,
hostname
,
realmHelper
);
methodCall
=
new
MethodCallHelper
(
realmHelper
);
}
@Override
...
...
app/src/main/java/chat/rocket/android/service/observer/LoadMessageProcedureObserver.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
service
.
observer
;
import
android.content.Context
;
import
org.json.JSONObject
;
import
java.util.List
;
import
chat.rocket.android.api.MethodCallHelper
;
import
chat.rocket.android.log.RCLog
;
import
chat.rocket.android.service.DDPClientRef
;
import
chat.rocket.core.SyncState
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.persistence.realm.models.ddp.RealmMessage
;
...
...
@@ -11,8 +15,6 @@ import chat.rocket.persistence.realm.models.internal.LoadMessageProcedure;
import
io.realm.Realm
;
import
io.realm.RealmResults
;
import
io.realm.Sort
;
import
java.util.List
;
import
org.json.JSONObject
;
/**
* Background process for loading messages.
...
...
@@ -22,9 +24,9 @@ public class LoadMessageProcedureObserver extends AbstractModelObserver<LoadMess
private
final
MethodCallHelper
methodCall
;
public
LoadMessageProcedureObserver
(
Context
context
,
String
hostname
,
RealmHelper
realmHelper
,
DDPClientRef
ddpClientRef
)
{
super
(
context
,
hostname
,
realmHelper
,
ddpClientRef
);
methodCall
=
new
MethodCallHelper
(
realmHelper
,
ddpClientRef
);
RealmHelper
realmHelper
)
{
super
(
context
,
hostname
,
realmHelper
);
methodCall
=
new
MethodCallHelper
(
realmHelper
);
}
@Override
...
...
app/src/main/java/chat/rocket/android/service/observer/MethodCallObserver.java
View file @
5bbd3f7f
...
...
@@ -8,7 +8,7 @@ import java.util.List;
import
chat.rocket.android.helper.CheckSum
;
import
chat.rocket.android.helper.LogIfError
;
import
chat.rocket.android
.service.DDPClientRef
;
import
chat.rocket.android
_ddp.DDPClient
;
import
chat.rocket.android_ddp.DDPClientCallback
;
import
chat.rocket.core.SyncState
;
import
chat.rocket.persistence.realm.RealmHelper
;
...
...
@@ -27,8 +27,8 @@ public class MethodCallObserver extends AbstractModelObserver<MethodCall> {
* constructor.
*/
public
MethodCallObserver
(
Context
context
,
String
hostname
,
RealmHelper
realmHelper
,
DDPClientRef
ddpClientRef
)
{
super
(
context
,
hostname
,
realmHelper
,
ddpClientRef
);
RealmHelper
realmHelper
)
{
super
(
context
,
hostname
,
realmHelper
);
realmHelper
.
executeTransaction
(
realm
->
{
// resume pending operations.
RealmResults
<
MethodCall
>
pendingMethodCalls
=
realm
.
where
(
MethodCall
.
class
)
...
...
@@ -99,7 +99,7 @@ public class MethodCallObserver extends AbstractModelObserver<MethodCall> {
.
put
(
MethodCall
.
ID
,
methodCallId
)
.
put
(
MethodCall
.
SYNC_STATE
,
SyncState
.
SYNCING
))
).
onSuccessTask
(
task
->
ddpClientRef
.
get
().
rpc
(
methodCallId
,
methodName
,
params
,
timeout
)
DDPClient
.
get
().
rpc
(
methodCallId
,
methodName
,
params
,
timeout
)
.
onSuccessTask
(
_task
->
realmHelper
.
executeTransaction
(
realm
->
{
String
json
=
_task
.
getResult
().
result
;
return
realm
.
createOrUpdateObjectFromJson
(
MethodCall
.
class
,
new
JSONObject
()
...
...
app/src/main/java/chat/rocket/android/service/observer/NewMessageObserver.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
service
.
observer
;
import
android.content.Context
;
import
io.realm.Realm
;
import
io.realm.RealmResults
;
import
org.json.JSONObject
;
import
java.util.List
;
import
chat.rocket.android.api.MethodCallHelper
;
import
chat.rocket.android.helper.LogIfError
;
import
chat.rocket.android.log.RCLog
;
import
chat.rocket.core.SyncState
;
import
chat.rocket.persistence.realm.models.ddp.RealmMessage
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.android.service.DDPClientRef
;
import
chat.rocket.persistence.realm.models.ddp.RealmMessage
;
import
io.realm.Realm
;
import
io.realm.RealmResults
;
/**
* Observe messages for sending.
...
...
@@ -21,9 +22,9 @@ public class NewMessageObserver extends AbstractModelObserver<RealmMessage> {
private
final
MethodCallHelper
methodCall
;
public
NewMessageObserver
(
Context
context
,
String
hostname
,
RealmHelper
realmHelper
,
DDPClientRef
ddpClientRef
)
{
super
(
context
,
hostname
,
realmHelper
,
ddpClientRef
);
methodCall
=
new
MethodCallHelper
(
realmHelper
,
ddpClientRef
);
public
NewMessageObserver
(
Context
context
,
String
hostname
,
RealmHelper
realmHelper
)
{
super
(
context
,
hostname
,
realmHelper
);
methodCall
=
new
MethodCallHelper
(
realmHelper
);
realmHelper
.
executeTransaction
(
realm
->
{
// resume pending operations.
...
...
app/src/main/java/chat/rocket/android/service/observer/PushSettingsObserver.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
service
.
observer
;
import
android.content.Context
;
import
io.realm.Realm
;
import
io.realm.RealmResults
;
import
java.util.List
;
import
chat.rocket.android.helper.GcmPushSettingHelper
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.persistence.realm.models.ddp.RealmPublicSetting
;
import
chat.rocket.persistence.realm.models.internal.GcmPushRegistration
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.android.service.DDPClientRef
;
import
io.realm.Realm
;
import
io.realm.RealmResults
;
public
class
PushSettingsObserver
extends
AbstractModelObserver
<
RealmPublicSetting
>
{
public
PushSettingsObserver
(
Context
context
,
String
hostname
,
RealmHelper
realmHelper
,
DDPClientRef
ddpClientRef
)
{
super
(
context
,
hostname
,
realmHelper
,
ddpClientRef
);
RealmHelper
realmHelper
)
{
super
(
context
,
hostname
,
realmHelper
);
}
@Override
...
...
app/src/main/java/chat/rocket/android/service/observer/SessionObserver.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
service
.
observer
;
import
android.content.Context
;
import
io.realm.Realm
;
import
io.realm.RealmResults
;
import
java.util.List
;
import
chat.rocket.android.RocketChatCache
;
import
chat.rocket.android.api.RaixPushHelper
;
import
chat.rocket.android.helper.LogIfError
;
import
chat.rocket.android.service.internal.StreamRoomMessageManager
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.persistence.realm.models.internal.GetUsersOfRoomsProcedure
;
import
chat.rocket.persistence.realm.models.internal.LoadMessageProcedure
;
import
chat.rocket.persistence.realm.models.internal.MethodCall
;
import
chat.rocket.persistence.realm.models.internal.RealmSession
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.android.service.DDPClientRef
;
import
chat.rocket.android.service.internal.StreamRoomMessageManager
;
import
hugo.weaving.DebugLog
;
import
io.realm.Realm
;
import
io.realm.RealmResults
;
/**
* Observes user is logged into server.
...
...
@@ -29,13 +29,13 @@ public class SessionObserver extends AbstractModelObserver<RealmSession> {
* constructor.
*/
public
SessionObserver
(
Context
context
,
String
hostname
,
RealmHelper
realmHelper
,
DDPClientRef
ddpClientRef
)
{
super
(
context
,
hostname
,
realmHelper
,
ddpClientRef
);
RealmHelper
realmHelper
)
{
super
(
context
,
hostname
,
realmHelper
);
count
=
0
;
streamNotifyMessage
=
new
StreamRoomMessageManager
(
context
,
hostname
,
realmHelper
,
ddpClientRef
);
pushHelper
=
new
RaixPushHelper
(
realmHelper
,
ddpClientRef
);
new
StreamRoomMessageManager
(
context
,
hostname
,
realmHelper
);
pushHelper
=
new
RaixPushHelper
(
realmHelper
);
}
@Override
...
...
app/src/main/java/chat/rocket/android/service/observer/TokenLoginObserver.java
deleted
100644 → 0
View file @
1f3713b3
package
chat
.
rocket
.
android
.
service
.
observer
;
import
android.content.Context
;
import
io.realm.Realm
;
import
io.realm.RealmResults
;
import
java.util.List
;
import
chat.rocket.android.api.MethodCallHelper
;
import
chat.rocket.android.helper.LogIfError
;
import
chat.rocket.persistence.realm.models.internal.RealmSession
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.android.service.DDPClientRef
;
public
class
TokenLoginObserver
extends
AbstractModelObserver
<
RealmSession
>
{
private
final
MethodCallHelper
methodCall
;
public
TokenLoginObserver
(
Context
context
,
String
hostname
,
RealmHelper
realmHelper
,
DDPClientRef
ddpClientRef
)
{
super
(
context
,
hostname
,
realmHelper
,
ddpClientRef
);
methodCall
=
new
MethodCallHelper
(
realmHelper
,
ddpClientRef
);
}
@Override
public
RealmResults
<
RealmSession
>
queryItems
(
Realm
realm
)
{
return
realm
.
where
(
RealmSession
.
class
)
.
isNotNull
(
RealmSession
.
TOKEN
)
.
equalTo
(
RealmSession
.
TOKEN_VERIFIED
,
false
)
.
isNull
(
RealmSession
.
ERROR
)
.
findAll
();
}
@Override
public
void
onUpdateResults
(
List
<
RealmSession
>
results
)
{
if
(
results
.
isEmpty
())
{
return
;
}
RealmSession
session
=
results
.
get
(
0
);
methodCall
.
loginWithToken
(
session
.
getToken
()).
continueWith
(
new
LogIfError
());
}
}
app/src/main/res/anim/slide_in.xml
0 → 100644
View file @
5bbd3f7f
<?xml version="1.0" encoding="utf-8"?>
<set
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:shareInterpolator=
"true"
android:interpolator=
"@android:anim/decelerate_interpolator"
>
<translate
android:duration=
"@android:integer/config_mediumAnimTime"
android:fromYDelta=
"100%p"
android:toYDelta=
"0"
>
</translate>
</set>
\ No newline at end of file
app/src/main/res/anim/slide_out.xml
0 → 100644
View file @
5bbd3f7f
<?xml version="1.0" encoding="utf-8"?>
<set
xmlns:android=
"http://schemas.android.com/apk/res/android"
>
<translate
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:duration=
"@android:integer/config_mediumAnimTime"
android:fromYDelta=
"0%p"
android:toYDelta=
"0"
>
</translate>
</set>
\ No newline at end of file
app/src/main/res/values/strings.xml
View file @
5bbd3f7f
...
...
@@ -27,8 +27,11 @@
<string
name=
"sending"
>
Sending…
</string>
<string
name=
"not_synced"
>
Not synced
</string>
<string
name=
"failed_to_sync"
>
Failed to sync
</string>
<string
name=
"failed_to_delete"
>
Failed to delete
</string>
<string
name=
"failed_to_delete_message"
>
The message could not be deleted at this time. Please try again later
</string>
<string
name=
"resend"
>
Resend
</string>
<string
name=
"discard"
>
Discard
</string>
<string
name=
"ok"
>
OK
</string>
<plurals
name=
"fmt_dialog_view_latest_message_title"
>
<item
quantity=
"one"
>
New %d message
</item>
...
...
@@ -45,7 +48,7 @@
<string
name=
"dialog_user_registration_password"
>
Password
</string>
<string
name=
"fragment_home_welcome_message"
>
Welcome to Rocket.Chat.Android\nSelect a channel from the drawer.
</string>
<string
name=
"fragment_input_hostname_hostname"
>
Hostname
</string>
<string
name=
"fragment_input_hostname_server_hint"
>
demo
.rocket.chat
</string>
<string
name=
"fragment_input_hostname_server_hint"
>
open
.rocket.chat
</string>
<string
name=
"fragment_input_hostname_connect"
>
CONNECT
</string>
<string
name=
"fragment_login_username_or_email"
>
Username or email
</string>
<string
name=
"fragment_login_password"
>
Password
</string>
...
...
app/src/test/kotlin/chat.rocket.android/RocketChatCacheTest.kt
deleted
100644 → 0
View file @
1f3713b3
package
chat.rocket.android;
import
android.content.Context
import
chat.rocket.core.utils.Pair
import
org.hamcrest.CoreMatchers.equalTo
import
org.json.JSONObject
import
org.junit.Assert.assertThat
import
org.junit.Before
import
org.junit.Test
import
org.junit.runner.RunWith
import
org.mockito.Mockito.*
import
org.mockito.junit.MockitoJUnitRunner
@RunWith
(
MockitoJUnitRunner
::
class
)
class
RocketChatCacheTest
{
lateinit
var
cache
:
RocketChatCache
@Before
fun
setup
()
{
val
mockedContext
=
mock
(
Context
::
class
.
java
)
val
mockAppContext
=
mock
(
Context
::
class
.
java
)
`when`
(
mockedContext
.
applicationContext
).
thenReturn
(
mockAppContext
)
cache
=
spy
(
RocketChatCache
(
mockedContext
))
}
@Test
fun
getServerList_ShouldReturnHostnameList
()
{
val
hostnameList
=
JSONObject
()
.
put
(
"http://demo.rocket.chat"
,
"images/logo/logo.png"
)
.
put
(
"http://192.168.0.6:3000"
,
"images/icon.svg"
)
.
toString
()
doReturn
(
hostnameList
).
`when`
(
cache
).
getString
(
"KEY_HOSTNAME_LIST"
,
null
)
val
expectedServerList
=
mutableListOf
(
Pair
(
"http://192.168.0.6:3000"
,
"http://192.168.0.6:3000/images/icon.svg"
),
Pair
(
"http://demo.rocket.chat"
,
"http://demo.rocket.chat/images/logo/logo.png"
))
val
serverList
=
cache
.
serverList
assertThat
(
serverList
,
equalTo
(
expectedServerList
))
}
}
\ No newline at end of file
app/src/test/kotlin/chat.rocket.android/push/PushManagerTest.kt
0 → 100644
View file @
5bbd3f7f
package
chat.rocket.android.push
import
android.app.Application
import
android.content.Context
import
android.content.res.Resources
import
android.os.Bundle
import
chat.rocket.android.BuildConfig
import
chat.rocket.android.R
import
chat.rocket.android.push.PushManager.PushMessage
import
com.nhaarman.mockito_kotlin.*
import
org.amshove.kluent.`should
equal
`
import
org.junit.Before
import
org.junit.Test
import
org.junit.runner.RunWith
import
org.mockito.ArgumentMatchers.anyString
import
org.mockito.MockitoAnnotations
import
org.robolectric.RobolectricTestRunner
import
org.robolectric.RuntimeEnvironment
import
org.robolectric.annotation.Config
import
kotlin.test.assertTrue
@RunWith
(
RobolectricTestRunner
::
class
)
@Config
(
constants
=
BuildConfig
::
class
,
application
=
PushManagerTest
.
StubApplication
::
class
,
sdk
=
intArrayOf
(
23
))
class
PushManagerTest
{
val
EJSON
=
"""
{
"host":"https://open.rocket.chat/",
"rid":"FaXMyHqbNJbPq6Ym9uWiyfQkgekhXywvKw",
"sender":{
"_id":"uWiFa3adOi0adac",
"username":"jean-luc.picard",
"name":"Jean-Luc Picard"
},
"type":"d",
"name":null
}
"""
val
EJSON_NO_SENDER
=
"""
{
"host":"https://open.rocket.chat/",
"rid":"FaXMyHqbNJbPq6Ym9uWiyfQkgekhXywvKw",
"sender":null,
"type":"d",
"name":null
}
"""
lateinit
var
data
:
Bundle
lateinit
var
pushManager
:
PushManager
lateinit
var
context
:
Context
@Before
fun
setUp
()
{
MockitoAnnotations
.
initMocks
(
this
)
data
=
Bundle
()
data
.
putString
(
"message"
,
"Hello"
)
data
.
putString
(
"title"
,
"jean-luc.picard"
)
data
.
putString
(
"ejson"
,
EJSON
)
data
.
putString
(
"notId"
,
"1"
)
context
=
spy
(
RuntimeEnvironment
.
application
)
pushManager
=
spy
(
PushManager
)
val
res
=
mock
<
Resources
>
{
on
{
getColor
(
any
())
}
doReturn
0
on
{
getIdentifier
(
anyString
(),
anyString
(),
any
())
}
doReturn
R
.
drawable
.
notification_icon_background
on
{
getConfiguration
()
}
doReturn
RuntimeEnvironment
.
application
.
resources
.
configuration
}
whenever
(
context
.
resources
).
doReturn
(
res
)
whenever
(
context
.
applicationContext
).
doReturn
(
context
)
}
@Test
fun
`
should
create
PushMessage
without
throwing
`
()
{
PushMessage
(
null
,
null
,
null
,
null
,
null
,
"xxx"
,
null
,
null
)
}
@Test
fun
`
given
data
shoud
show
notification
`
()
{
pushManager
.
handle
(
context
,
data
)
val
push
=
PushMessage
(
title
=
data
[
"title"
]
as
String
,
message
=
data
[
"message"
]
as
String
,
ejson
=
EJSON
,
notificationId
=
"1"
)
verify
(
pushManager
,
times
(
1
)).
showNotification
(
context
,
push
)
}
@Test
fun
`
given
required
data
is
missing
do
not
show
notification
`
()
{
val
bundle
=
Bundle
()
pushManager
.
handle
(
context
,
bundle
)
verify
(
pushManager
,
never
()).
showNotification
(
any
(),
any
())
bundle
.
putString
(
"title"
,
"jean-luc.picard"
)
bundle
.
putString
(
"message"
,
"Hello!"
)
pushManager
.
handle
(
context
,
bundle
)
verify
(
pushManager
,
never
()).
showNotification
(
any
(),
any
())
bundle
.
clear
()
bundle
.
putString
(
"ejson"
,
EJSON
)
bundle
.
putString
(
"message"
,
"Hello!"
)
pushManager
.
handle
(
context
,
bundle
)
verify
(
pushManager
,
never
()).
showNotification
(
any
(),
any
())
bundle
.
clear
()
bundle
.
putString
(
"ejson"
,
EJSON
)
bundle
.
putString
(
"title"
,
"jean-luc.picard"
)
pushManager
.
handle
(
context
,
bundle
)
verify
(
pushManager
,
never
()).
showNotification
(
any
(),
any
())
}
@Test
fun
`
given
data
should
deserialize
correctly
`
()
{
pushManager
.
handle
(
context
,
data
)
val
push
=
PushMessage
(
data
.
getString
(
"title"
),
data
.
getString
(
"message"
),
null
,
EJSON
,
null
,
data
.
getString
(
"notId"
),
null
,
null
)
verify
(
pushManager
,
times
(
1
)).
showNotification
(
context
,
push
)
push
.
title
`
should
equal
`
"jean-luc.picard"
push
.
message
`
should
equal
`
"Hello"
val
sender
=
push
.
sender
assertTrue
(
sender
!=
null
)
sender
?.
_id
`
should
equal
`
"uWiFa3adOi0adac"
sender
?.
name
`
should
equal
`
"Jean-Luc Picard"
sender
?.
username
`
should
equal
`
"jean-luc.picard"
}
@Test
fun
`
given
that
only
sender
is
missing
show
notification
`
()
{
val
bundle
=
Bundle
()
bundle
.
putString
(
"title"
,
"jean-luc.picard"
)
bundle
.
putString
(
"message"
,
"Hello"
)
bundle
.
putString
(
"ejson"
,
EJSON_NO_SENDER
)
pushManager
.
handle
(
context
,
bundle
)
verify
(
pushManager
,
times
(
1
)).
showNotification
(
any
(),
any
())
}
internal
class
StubApplication
:
Application
()
}
\ No newline at end of file
app/src/test/kotlin/chat/rocket/android/api/rest/RestApiHelperTest.kt
View file @
5bbd3f7f
...
...
@@ -8,83 +8,83 @@ class RestApiHelperTest {
@Test
fun
getEndpointUrlForMessagesTest
()
{
assertEquals
(
"https://
demo.rocket.chat/api/v1/channels.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_CHANNEL
,
"demo
.rocket.chat"
))
assertEquals
(
"https://
demo.rocket.chat/api/v1/groups.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_GROUP
,
"demo
.rocket.chat"
))
assertEquals
(
"https://
demo.rocket.chat/api/v1/dm.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_DIRECT_MESSAGE
,
"demo
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat/api/v1/channels.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_CHANNEL
,
"open
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat/api/v1/groups.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_GROUP
,
"open
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat/api/v1/dm.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_DIRECT_MESSAGE
,
"open
.rocket.chat"
))
assertEquals
(
"https://
demo.rocket.chat/api/v1/channels.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_CHANNEL
,
"https://demo
.rocket.chat"
))
assertEquals
(
"https://
demo.rocket.chat/api/v1/groups.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_GROUP
,
"https://demo
.rocket.chat"
))
assertEquals
(
"https://
demo.rocket.chat/api/v1/dm.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_DIRECT_MESSAGE
,
"https://demo
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat/api/v1/channels.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_CHANNEL
,
"https://open
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat/api/v1/groups.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_GROUP
,
"https://open
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat/api/v1/dm.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_DIRECT_MESSAGE
,
"https://open
.rocket.chat"
))
assertEquals
(
"https://
demo.rocket.chat/api/v1/channels.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_CHANNEL
,
"http://demo
.rocket.chat"
))
assertEquals
(
"https://
demo.rocket.chat/api/v1/groups.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_GROUP
,
"http://demo
.rocket.chat"
))
assertEquals
(
"https://
demo.rocket.chat/api/v1/dm.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_DIRECT_MESSAGE
,
"http://demo
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat/api/v1/channels.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_CHANNEL
,
"http://open
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat/api/v1/groups.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_GROUP
,
"http://open
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat/api/v1/dm.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_DIRECT_MESSAGE
,
"http://open
.rocket.chat"
))
assertEquals
(
"https://www.
demo.rocket.chat/api/v1/channels.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_CHANNEL
,
"www.demo
.rocket.chat"
))
assertEquals
(
"https://www.
demo.rocket.chat/api/v1/groups.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_GROUP
,
"www.demo
.rocket.chat"
))
assertEquals
(
"https://www.
demo.rocket.chat/api/v1/dm.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_DIRECT_MESSAGE
,
"www.demo
.rocket.chat"
))
assertEquals
(
"https://www.
open.rocket.chat/api/v1/channels.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_CHANNEL
,
"www.open
.rocket.chat"
))
assertEquals
(
"https://www.
open.rocket.chat/api/v1/groups.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_GROUP
,
"www.open
.rocket.chat"
))
assertEquals
(
"https://www.
open.rocket.chat/api/v1/dm.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_DIRECT_MESSAGE
,
"www.open
.rocket.chat"
))
assertEquals
(
"https://www.
demo.rocket.chat/api/v1/channels.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_CHANNEL
,
"https://www.demo
.rocket.chat"
))
assertEquals
(
"https://www.
demo.rocket.chat/api/v1/groups.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_GROUP
,
"https://www.demo
.rocket.chat"
))
assertEquals
(
"https://www.
demo.rocket.chat/api/v1/dm.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_DIRECT_MESSAGE
,
"https://www.demo
.rocket.chat"
))
assertEquals
(
"https://www.
open.rocket.chat/api/v1/channels.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_CHANNEL
,
"https://www.open
.rocket.chat"
))
assertEquals
(
"https://www.
open.rocket.chat/api/v1/groups.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_GROUP
,
"https://www.open
.rocket.chat"
))
assertEquals
(
"https://www.
open.rocket.chat/api/v1/dm.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_DIRECT_MESSAGE
,
"https://www.open
.rocket.chat"
))
assertEquals
(
"https://www.
demo.rocket.chat/api/v1/channels.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_CHANNEL
,
"http://www.demo
.rocket.chat"
))
assertEquals
(
"https://www.
demo.rocket.chat/api/v1/groups.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_GROUP
,
"http://www.demo
.rocket.chat"
))
assertEquals
(
"https://www.
demo.rocket.chat/api/v1/dm.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_DIRECT_MESSAGE
,
"http://www.demo
.rocket.chat"
))
assertEquals
(
"https://www.
open.rocket.chat/api/v1/channels.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_CHANNEL
,
"http://www.open
.rocket.chat"
))
assertEquals
(
"https://www.
open.rocket.chat/api/v1/groups.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_GROUP
,
"http://www.open
.rocket.chat"
))
assertEquals
(
"https://www.
open.rocket.chat/api/v1/dm.messages"
,
RestApiHelper
.
getEndpointUrlForMessages
(
Room
.
TYPE_DIRECT_MESSAGE
,
"http://www.open
.rocket.chat"
))
}
@Test
fun
getEndpointUrlForFileListTest
()
{
assertEquals
(
"https://
demo.rocket.chat/api/v1/channels.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_CHANNEL
,
"demo
.rocket.chat"
))
assertEquals
(
"https://
demo.rocket.chat/api/v1/groups.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_GROUP
,
"demo
.rocket.chat"
))
assertEquals
(
"https://
demo.rocket.chat/api/v1/dm.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_DIRECT_MESSAGE
,
"demo
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat/api/v1/channels.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_CHANNEL
,
"open
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat/api/v1/groups.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_GROUP
,
"open
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat/api/v1/dm.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_DIRECT_MESSAGE
,
"open
.rocket.chat"
))
assertEquals
(
"https://
demo.rocket.chat/api/v1/channels.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_CHANNEL
,
"https://demo
.rocket.chat"
))
assertEquals
(
"https://
demo.rocket.chat/api/v1/groups.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_GROUP
,
"https://demo
.rocket.chat"
))
assertEquals
(
"https://
demo.rocket.chat/api/v1/dm.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_DIRECT_MESSAGE
,
"https://demo
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat/api/v1/channels.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_CHANNEL
,
"https://open
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat/api/v1/groups.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_GROUP
,
"https://open
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat/api/v1/dm.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_DIRECT_MESSAGE
,
"https://open
.rocket.chat"
))
assertEquals
(
"https://
demo.rocket.chat/api/v1/channels.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_CHANNEL
,
"http://demo
.rocket.chat"
))
assertEquals
(
"https://
demo.rocket.chat/api/v1/groups.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_GROUP
,
"http://demo
.rocket.chat"
))
assertEquals
(
"https://
demo.rocket.chat/api/v1/dm.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_DIRECT_MESSAGE
,
"http://demo
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat/api/v1/channels.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_CHANNEL
,
"http://open
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat/api/v1/groups.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_GROUP
,
"http://open
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat/api/v1/dm.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_DIRECT_MESSAGE
,
"http://open
.rocket.chat"
))
assertEquals
(
"https://www.
demo.rocket.chat/api/v1/channels.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_CHANNEL
,
"www.demo
.rocket.chat"
))
assertEquals
(
"https://www.
demo.rocket.chat/api/v1/groups.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_GROUP
,
"www.demo
.rocket.chat"
))
assertEquals
(
"https://www.
demo.rocket.chat/api/v1/dm.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_DIRECT_MESSAGE
,
"www.demo
.rocket.chat"
))
assertEquals
(
"https://www.
open.rocket.chat/api/v1/channels.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_CHANNEL
,
"www.open
.rocket.chat"
))
assertEquals
(
"https://www.
open.rocket.chat/api/v1/groups.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_GROUP
,
"www.open
.rocket.chat"
))
assertEquals
(
"https://www.
open.rocket.chat/api/v1/dm.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_DIRECT_MESSAGE
,
"www.open
.rocket.chat"
))
assertEquals
(
"https://www.
demo.rocket.chat/api/v1/channels.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_CHANNEL
,
"https://www.demo
.rocket.chat"
))
assertEquals
(
"https://www.
demo.rocket.chat/api/v1/groups.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_GROUP
,
"https://www.demo
.rocket.chat"
))
assertEquals
(
"https://www.
demo.rocket.chat/api/v1/dm.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_DIRECT_MESSAGE
,
"https://www.demo
.rocket.chat"
))
assertEquals
(
"https://www.
open.rocket.chat/api/v1/channels.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_CHANNEL
,
"https://www.open
.rocket.chat"
))
assertEquals
(
"https://www.
open.rocket.chat/api/v1/groups.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_GROUP
,
"https://www.open
.rocket.chat"
))
assertEquals
(
"https://www.
open.rocket.chat/api/v1/dm.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_DIRECT_MESSAGE
,
"https://www.open
.rocket.chat"
))
assertEquals
(
"https://www.
demo.rocket.chat/api/v1/channels.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_CHANNEL
,
"http://www.demo
.rocket.chat"
))
assertEquals
(
"https://www.
demo.rocket.chat/api/v1/groups.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_GROUP
,
"http://www.demo
.rocket.chat"
))
assertEquals
(
"https://www.
demo.rocket.chat/api/v1/dm.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_DIRECT_MESSAGE
,
"http://www.demo
.rocket.chat"
))
assertEquals
(
"https://www.
open.rocket.chat/api/v1/channels.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_CHANNEL
,
"http://www.open
.rocket.chat"
))
assertEquals
(
"https://www.
open.rocket.chat/api/v1/groups.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_GROUP
,
"http://www.open
.rocket.chat"
))
assertEquals
(
"https://www.
open.rocket.chat/api/v1/dm.files"
,
RestApiHelper
.
getEndpointUrlForFileList
(
Room
.
TYPE_DIRECT_MESSAGE
,
"http://www.open
.rocket.chat"
))
}
@Test
fun
getEndpointUrlForMemberListTest
()
{
assertEquals
(
"https://
demo.rocket.chat/api/v1/channels.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_CHANNEL
,
"demo
.rocket.chat"
))
assertEquals
(
"https://
demo.rocket.chat/api/v1/groups.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_GROUP
,
"demo
.rocket.chat"
))
assertEquals
(
"https://
demo.rocket.chat/api/v1/dm.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_DIRECT_MESSAGE
,
"demo
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat/api/v1/channels.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_CHANNEL
,
"open
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat/api/v1/groups.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_GROUP
,
"open
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat/api/v1/dm.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_DIRECT_MESSAGE
,
"open
.rocket.chat"
))
assertEquals
(
"https://
demo.rocket.chat/api/v1/channels.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_CHANNEL
,
"https://demo
.rocket.chat"
))
assertEquals
(
"https://
demo.rocket.chat/api/v1/groups.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_GROUP
,
"https://demo
.rocket.chat"
))
assertEquals
(
"https://
demo.rocket.chat/api/v1/dm.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_DIRECT_MESSAGE
,
"https://demo
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat/api/v1/channels.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_CHANNEL
,
"https://open
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat/api/v1/groups.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_GROUP
,
"https://open
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat/api/v1/dm.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_DIRECT_MESSAGE
,
"https://open
.rocket.chat"
))
assertEquals
(
"https://
demo.rocket.chat/api/v1/channels.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_CHANNEL
,
"http://demo
.rocket.chat"
))
assertEquals
(
"https://
demo.rocket.chat/api/v1/groups.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_GROUP
,
"http://demo
.rocket.chat"
))
assertEquals
(
"https://
demo.rocket.chat/api/v1/dm.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_DIRECT_MESSAGE
,
"http://demo
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat/api/v1/channels.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_CHANNEL
,
"http://open
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat/api/v1/groups.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_GROUP
,
"http://open
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat/api/v1/dm.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_DIRECT_MESSAGE
,
"http://open
.rocket.chat"
))
assertEquals
(
"https://www.
demo.rocket.chat/api/v1/channels.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_CHANNEL
,
"www.demo
.rocket.chat"
))
assertEquals
(
"https://www.
demo.rocket.chat/api/v1/groups.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_GROUP
,
"www.demo
.rocket.chat"
))
assertEquals
(
"https://www.
demo.rocket.chat/api/v1/dm.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_DIRECT_MESSAGE
,
"www.demo
.rocket.chat"
))
assertEquals
(
"https://www.
open.rocket.chat/api/v1/channels.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_CHANNEL
,
"www.open
.rocket.chat"
))
assertEquals
(
"https://www.
open.rocket.chat/api/v1/groups.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_GROUP
,
"www.open
.rocket.chat"
))
assertEquals
(
"https://www.
open.rocket.chat/api/v1/dm.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_DIRECT_MESSAGE
,
"www.open
.rocket.chat"
))
assertEquals
(
"https://www.
demo.rocket.chat/api/v1/channels.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_CHANNEL
,
"https://www.demo
.rocket.chat"
))
assertEquals
(
"https://www.
demo.rocket.chat/api/v1/groups.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_GROUP
,
"https://www.demo
.rocket.chat"
))
assertEquals
(
"https://www.
demo.rocket.chat/api/v1/dm.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_DIRECT_MESSAGE
,
"https://www.demo
.rocket.chat"
))
assertEquals
(
"https://www.
open.rocket.chat/api/v1/channels.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_CHANNEL
,
"https://www.open
.rocket.chat"
))
assertEquals
(
"https://www.
open.rocket.chat/api/v1/groups.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_GROUP
,
"https://www.open
.rocket.chat"
))
assertEquals
(
"https://www.
open.rocket.chat/api/v1/dm.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_DIRECT_MESSAGE
,
"https://www.open
.rocket.chat"
))
assertEquals
(
"https://www.
demo.rocket.chat/api/v1/channels.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_CHANNEL
,
"http://www.demo
.rocket.chat"
))
assertEquals
(
"https://www.
demo.rocket.chat/api/v1/groups.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_GROUP
,
"http://www.demo
.rocket.chat"
))
assertEquals
(
"https://www.
demo.rocket.chat/api/v1/dm.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_DIRECT_MESSAGE
,
"http://www.demo
.rocket.chat"
))
assertEquals
(
"https://www.
open.rocket.chat/api/v1/channels.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_CHANNEL
,
"http://www.open
.rocket.chat"
))
assertEquals
(
"https://www.
open.rocket.chat/api/v1/groups.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_GROUP
,
"http://www.open
.rocket.chat"
))
assertEquals
(
"https://www.
open.rocket.chat/api/v1/dm.members"
,
RestApiHelper
.
getEndpointUrlForMemberList
(
Room
.
TYPE_DIRECT_MESSAGE
,
"http://www.open
.rocket.chat"
))
}
@Test
...
...
app/src/test/kotlin/chat/rocket/android/helper/UrlHelperTest.kt
View file @
5bbd3f7f
...
...
@@ -7,31 +7,31 @@ class UrlHelperTest {
@Test
fun
removeUriSchemeTest
()
{
assertEquals
(
"
demo.rocket.chat"
,
UrlHelper
.
removeUriScheme
(
"https://demo
.rocket.chat"
))
assertEquals
(
"
demo.rocket.chat"
,
UrlHelper
.
removeUriScheme
(
"http://demo
.rocket.chat"
))
assertEquals
(
"
demo.rocket.chat"
,
UrlHelper
.
removeUriScheme
(
"demo
.rocket.chat"
))
assertEquals
(
"
open.rocket.chat"
,
UrlHelper
.
removeUriScheme
(
"https://open
.rocket.chat"
))
assertEquals
(
"
open.rocket.chat"
,
UrlHelper
.
removeUriScheme
(
"http://open
.rocket.chat"
))
assertEquals
(
"
open.rocket.chat"
,
UrlHelper
.
removeUriScheme
(
"open
.rocket.chat"
))
}
@Test
fun
getSafeHostnameTest
()
{
assertEquals
(
"https://
demo.rocket.chat"
,
UrlHelper
.
getSafeHostname
(
"https://demo
.rocket.chat"
))
assertEquals
(
"https://
demo.rocket.chat"
,
UrlHelper
.
getSafeHostname
(
"http://demo
.rocket.chat"
))
assertEquals
(
"https://
demo.rocket.chat"
,
UrlHelper
.
getSafeHostname
(
"demo
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat"
,
UrlHelper
.
getSafeHostname
(
"https://open
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat"
,
UrlHelper
.
getSafeHostname
(
"http://open
.rocket.chat"
))
assertEquals
(
"https://
open.rocket.chat"
,
UrlHelper
.
getSafeHostname
(
"open
.rocket.chat"
))
}
@Test
fun
getUrlTest
()
{
assertEquals
(
"https://
demo.rocket.chat/GENERAL/file.txt"
,
UrlHelper
.
getSafeUrl
(
"https://demo
.rocket.chat/GENERAL/file.txt"
))
assertEquals
(
"http://
demo.rocket.chat/GENERAL/file.txt"
,
UrlHelper
.
getSafeUrl
(
"http://demo
.rocket.chat/GENERAL/file.txt"
))
assertEquals
(
"
demo.rocket.chat/GENERAL/file.txt"
,
UrlHelper
.
getSafeUrl
(
"demo
.rocket.chat/GENERAL/file.txt"
))
assertEquals
(
"
demo.rocket.chat/GENERAL/a%20sample%20file.txt"
,
UrlHelper
.
getSafeUrl
(
"demo
.rocket.chat/GENERAL/a sample file.txt"
))
assertEquals
(
"
demo.rocket.chat/GENERAL/file.txt"
,
UrlHelper
.
getSafeUrl
(
"demo
.rocket.chat\\/GENERAL\\/file.txt"
))
assertEquals
(
"https://
open.rocket.chat/GENERAL/file.txt"
,
UrlHelper
.
getSafeUrl
(
"https://open
.rocket.chat/GENERAL/file.txt"
))
assertEquals
(
"http://
open.rocket.chat/GENERAL/file.txt"
,
UrlHelper
.
getSafeUrl
(
"http://open
.rocket.chat/GENERAL/file.txt"
))
assertEquals
(
"
open.rocket.chat/GENERAL/file.txt"
,
UrlHelper
.
getSafeUrl
(
"open
.rocket.chat/GENERAL/file.txt"
))
assertEquals
(
"
open.rocket.chat/GENERAL/a%20sample%20file.txt"
,
UrlHelper
.
getSafeUrl
(
"open
.rocket.chat/GENERAL/a sample file.txt"
))
assertEquals
(
"
open.rocket.chat/GENERAL/file.txt"
,
UrlHelper
.
getSafeUrl
(
"open
.rocket.chat\\/GENERAL\\/file.txt"
))
}
@Test
fun
getAttachmentLinkTest
()
{
assertEquals
(
"https://
demo.rocket.chat/file-upload/aFileId/aFileName.txt"
,
UrlHelper
.
getAttachmentLink
(
"https://demo
.rocket.chat"
,
"aFileId"
,
"aFileName.txt"
))
assertEquals
(
"https://
demo.rocket.chat/file-upload/aFileId/aFileName.txt"
,
UrlHelper
.
getAttachmentLink
(
"http://demo
.rocket.chat"
,
"aFileId"
,
"aFileName.txt"
))
assertEquals
(
"https://
demo.rocket.chat/file-upload/aFileId/aFileName.txt"
,
UrlHelper
.
getAttachmentLink
(
"demo
.rocket.chat"
,
"aFileId"
,
"aFileName.txt"
))
assertEquals
(
"https://
open.rocket.chat/file-upload/aFileId/aFileName.txt"
,
UrlHelper
.
getAttachmentLink
(
"https://open
.rocket.chat"
,
"aFileId"
,
"aFileName.txt"
))
assertEquals
(
"https://
open.rocket.chat/file-upload/aFileId/aFileName.txt"
,
UrlHelper
.
getAttachmentLink
(
"http://open
.rocket.chat"
,
"aFileId"
,
"aFileName.txt"
))
assertEquals
(
"https://
open.rocket.chat/file-upload/aFileId/aFileName.txt"
,
UrlHelper
.
getAttachmentLink
(
"open
.rocket.chat"
,
"aFileId"
,
"aFileName.txt"
))
}
}
\ No newline at end of file
build.gradle
View file @
5bbd3f7f
// Top-level build file where you can add configuration options common to all sub-projects/modules.
apply
from:
rootProject
.
file
(
'dependencies.gradle'
)
ext
{
compileSdkVersion
=
26
targetSdkVersion
=
26
buildToolsVersion
=
"26.0.2"
}
buildscript
{
repositories
{
google
()
jcenter
()
maven
{
url
'https://maven.fabric.io/public'
}
maven
{
url
'http://oss.jfrog.org/artifactory/oss-snapshot-local'
}
}
dependencies
{
classpath
'com.android.tools.build:gradle:3.0.1'
classpath
"org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.60"
classpath
'io.realm:realm-gradle-plugin:4.2.0'
classpath
'com.jakewharton.hugo:hugo-plugin:1.2.1'
classpath
'com.google.gms:google-services:3.0.0'
classpath
'com.github.triplet.gradle:play-publisher:1.1.5'
classpath
'io.fabric.tools:gradle:1.+'
}
// Exclude the version that the android plugin depends on.
configurations
.
classpath
.
exclude
group:
'com.android.tools.external.lombok'
}
allprojects
{
repositories
{
google
()
jcenter
()
mavenCentral
()
maven
{
url
'https://github.com/lijingle1/stetho-realm/raw/master/maven-repo'
}
maven
{
url
'http://dl.bintray.com/amulyakhare/maven'
}
//for TextDrawable.
maven
{
url
"https://clojars.org/repo/"
}
//for icepick.
maven
{
url
'https://jitpack.io'
}
//for widget-fontawesome.
maven
{
url
"https://maven.google.com"
}
// for Support Library
.
maven
{
url
'http://oss.jfrog.org/artifactory/oss-snapshot-local'
}
//for widget-fontawesome
.
}
}
// This block encapsulates custom properties and makes them available to all modules in the project.
// You can also create properties to specify versions for dependencies.
// Having consistent versions between modules can avoid conflicts with behavior.
ext
{
compileSdkVersion
=
26
targetSdkVersion
=
26
buildToolsVersion
=
"26.0.0"
}
task
clean
(
type:
Delete
)
{
delete
rootProject
.
buildDir
...
...
circle.yml
View file @
5bbd3f7f
...
...
@@ -7,10 +7,15 @@
machine
:
environment
:
ANDROID_HOME
:
/usr/local/android-sdk-linux
GRADLE_OPTS
:
'
-Dorg.gradle.jvmargs="-Xmx1536m
-XX:MaxPermSize=512m
-XX:+HeapDumpOnOutOfMemoryError"'
GRADLE_OPTS
:
'
-Xmx1024m
-Dorg.gradle.jvmargs="-Xmx1024m
-XX:MaxPermSize=512m
-XX:+HeapDumpOnOutOfMemoryError"'
JAVA_OPTS
:
"
-Xms518m
-Xmx1536m"
dependencies
:
pre
:
-
sudo service mysql stop; sleep 5
-
sudo service mongod stop; sleep 5
-
sudo killall postgres; sleep 5
-
git fetch --tags
-
echo "sdk.dir="$ANDROID_HOME > local.properties
...
...
@@ -26,10 +31,10 @@ dependencies:
-
echo y | android update sdk --no-ui --all --filter android-26
-
echo y | android update sdk --no-ui --all --filter extra-android-m2repository,extra-android-support
-
echo y | android update sdk --no-ui --all --filter extra-google-m2repository,extra-google-google_play_services
-
echo y | android update sdk --no-ui --all --filter build-tools-26.0.
0
-
echo y | android update sdk --no-ui --all --filter build-tools-26.0.
2
cache_directories
:
-
/usr/local/android-sdk-linux/tools
-
/usr/local/android-sdk-linux/build-tools/26.0.
0
-
/usr/local/android-sdk-linux/build-tools/26.0.
2
test
:
override
:
...
...
dependencies.gradle
View file @
5bbd3f7f
ext
{
preDexLibs
=
"true"
!=
System
.
getenv
(
"CI"
)
supportLibraryVersion
=
"2
5.4.0
"
supportLibraryVersion
=
"2
7.0.1
"
constraintLayoutVersion
=
"1.0.2"
kotlinVersion
=
"1.1.
4-2
"
kotlinVersion
=
"1.1.
51
"
okHttpVersion
=
"3.9.0"
rxbindingVersion
=
'2.0.0'
supportDependencies
=
[
designSupportLibrary:
"com.android.support:design:${supportLibraryVersion}"
,
annotation
:
"com.android.support:support-annotations:${supportLibraryVersion}"
,
constrainLayout
:
"com.android.support.constraint:constraint-layout:${constraintLayoutVersion}"
,
kotlin
:
"org.jetbrains.kotlin:kotlin-stdlib-jre7:${kotlinVersion}"
,
constraintLayout
:
"com.android.support.constraint:constraint-layout:${constraintLayoutVersion}"
,
cardView
:
"com.android.support:cardview-v7:${supportLibraryVersion}"
,
supportV13
:
"com.android.support:support-v13:${supportLibraryVersion}"
,
multidex
:
"com.android.support:multidex:1.0.2"
]
extraDependencies
=
[
okHTTP
:
"com.squareup.okhttp3:okhttp:
3.8.0
"
,
okHTTP
:
"com.squareup.okhttp3:okhttp:
${okHttpVersion}
"
,
rxJava
:
"io.reactivex.rxjava2:rxjava:2.1.0"
,
boltTask
:
"com.parse.bolts:bolts-tasks:1.4.0"
,
rxAndroid
:
"io.reactivex.rxjava2:rxandroid:2.0.1"
,
textDrawable
:
"com.github.rocketchat:textdrawable:1.0.2"
textDrawable
:
"com.github.rocketchat:textdrawable:1.0.2"
,
optional
:
"com.hadisatrio:Optional:v1.0.1"
]
rxbindingDependencies
=
[
rxBinding
:
"com.jakewharton.rxbinding2:rxbinding:${rxbindingVersion}"
,
...
...
@@ -25,6 +28,7 @@ ext {
rxBindingAppcompact:
"com.jakewharton.rxbinding2:rxbinding-appcompat-v7:${rxbindingVersion}"
,
]
}
subprojects
{
project
.
plugins
.
whenPluginAdded
{
plugin
->
if
(
"com.android.build.gradle.AppPlugin"
==
plugin
.
class
.
name
)
{
...
...
gradle/wrapper/gradle-wrapper.properties
View file @
5bbd3f7f
#
Mon Dec 28 10:00:20 PST 2015
#
Tue Nov 07 03:05:05 BRST 2017
distributionBase
=
GRADLE_USER_HOME
distributionPath
=
wrapper/dists
zipStoreBase
=
GRADLE_USER_HOME
zipStorePath
=
wrapper/dists
distributionUrl
=
https
\:
//services.gradle.org/distributions/gradle-
3.4
-all.zip
distributionUrl
=
https
\:
//services.gradle.org/distributions/gradle-
4.1
-all.zip
log-wrapper/build.gradle
View file @
5bbd3f7f
apply
plugin:
'com.android.library'
buildscript
{
repositories
{
jcenter
()
}
dependencies
{
classpath
'com.android.tools.build:gradle:2.3.3'
}
}
android
{
compileSdkVersion
rootProject
.
ext
.
compileSdkVersion
buildToolsVersion
rootProject
.
ext
.
buildToolsVersion
...
...
persistence-realm/build.gradle
View file @
5bbd3f7f
...
...
@@ -2,21 +2,6 @@ apply plugin: 'com.android.library'
apply
plugin:
'kotlin-android'
apply
plugin:
'realm-android'
apply
plugin:
'com.jakewharton.hugo'
apply
plugin:
'me.tatarka.retrolambda'
buildscript
{
repositories
{
jcenter
()
}
dependencies
{
classpath
'com.android.tools.build:gradle:2.3.3'
classpath
"org.jetbrains.kotlin:kotlin-gradle-plugin:$rootProject.ext.kotlinVersion"
classpath
'io.realm:realm-gradle-plugin:2.3.2'
classpath
'me.tatarka:gradle-retrolambda:3.5.0'
classpath
'me.tatarka.retrolambda.projectlombok:lombok.ast:0.2.3.a2'
classpath
'com.jakewharton.hugo:hugo-plugin:1.2.1'
}
}
android
{
compileSdkVersion
rootProject
.
ext
.
compileSdkVersion
...
...
@@ -51,13 +36,11 @@ dependencies {
compile
extraDependencies
.
boltTask
compile
supportDependencies
.
annotation
compile
supportDependencies
.
designSupportLibrary
compile
supportDependencies
.
kotlin
compile
extraDependencies
.
rxAndroid
provided
extraDependencies
.
optional
testCompile
"org.jetbrains.kotlin:kotlin-test:$rootProject.ext.kotlinVersion"
testCompile
"org.jetbrains.kotlin:kotlin-test-junit:$rootProject.ext.kotlinVersion"
testCompile
'org.json:json:20170516'
testCompile
'org.skyscreamer:jsonassert:1.5.0'
compile
'com.github.akarnokd:rxjava2-interop:0.10.0'
provided
'com.hadisatrio:Optional:v1.0.1'
testCompile
'junit:junit:4.12'
}
persistence-realm/src/main/java/chat/rocket/persistence/realm/Migration.java
View file @
5bbd3f7f
package
chat
.
rocket
.
persistence
.
realm
;
import
io.realm.DynamicRealm
;
import
io.realm.FieldAttribute
;
import
io.realm.RealmMigration
;
import
io.realm.RealmObjectSchema
;
import
io.realm.RealmSchema
;
import
chat.rocket.persistence.realm.models.ddp.RealmMessage
;
import
chat.rocket.persistence.realm.models.ddp.RealmPermission
;
import
chat.rocket.persistence.realm.models.ddp.RealmRole
;
import
chat.rocket.persistence.realm.models.ddp.RealmRoomRole
;
import
chat.rocket.persistence.realm.models.ddp.RealmSpotlightRoom
;
import
chat.rocket.persistence.realm.models.ddp.RealmSpotlightUser
;
import
chat.rocket.persistence.realm.models.ddp.RealmUser
;
import
io.realm.DynamicRealm
;
import
io.realm.FieldAttribute
;
import
io.realm.RealmMigration
;
import
io.realm.RealmObjectSchema
;
import
io.realm.RealmSchema
;
public
class
Migration
implements
RealmMigration
{
@Override
...
...
@@ -68,6 +68,20 @@ public class Migration implements RealmMigration {
if
(
oldVersion
==
4
)
{
RealmObjectSchema
messageSchema
=
schema
.
get
(
"RealmMessage"
);
messageSchema
.
addField
(
RealmMessage
.
EDITED_AT
,
long
.
class
);
oldVersion
++;
}
if
(
oldVersion
==
5
)
{
RealmObjectSchema
userSchema
=
schema
.
get
(
"RealmUser"
);
try
{
userSchema
.
addField
(
RealmUser
.
NAME
,
String
.
class
);
}
catch
(
IllegalArgumentException
e
)
{
if
(
BuildConfig
.
DEBUG
)
{
e
.
printStackTrace
();
}
// ignore; it makes here if the schema for this model was already update before without migration
}
}
}
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/RealmAutoCompleteAdapter.java
View file @
5bbd3f7f
...
...
@@ -8,13 +8,14 @@ import android.view.ViewGroup;
import
android.widget.ArrayAdapter
;
import
android.widget.Filter
;
import
android.widget.TextView
;
import
io.realm.Realm
;
import
io.realm.RealmObject
;
import
io.realm.RealmResults
;
import
java.util.Collections
;
import
java.util.List
;
import
io.realm.Realm
;
import
io.realm.RealmObject
;
import
io.realm.RealmResults
;
/**
* ListAdapter for AutoCompleteTextView.
*/
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/RealmHelper.java
View file @
5bbd3f7f
...
...
@@ -3,18 +3,23 @@ package chat.rocket.persistence.realm;
import
android.annotation.SuppressLint
;
import
android.content.Context
;
import
android.os.Looper
;
import
io.realm.Realm
;
import
io.realm.RealmConfiguration
;
import
io.realm.RealmObject
;
import
io.realm.RealmQuery
;
import
io.realm.RealmResults
;
import
org.json.JSONException
;
import
java.util.Collections
;
import
java.util.List
;
import
bolts.Task
;
import
bolts.TaskCompletionSource
;
import
chat.rocket.android.log.RCLog
;
import
io.reactivex.Flowable
;
import
io.realm.Realm
;
import
io.realm.RealmConfiguration
;
import
io.realm.RealmModel
;
import
io.realm.RealmObject
;
import
io.realm.RealmQuery
;
import
io.realm.RealmResults
;
import
io.realm.log.RealmLog
;
@SuppressLint
(
"NewApi"
)
public
class
RealmHelper
{
...
...
@@ -164,6 +169,25 @@ public class RealmHelper {
return
constructor
.
getNewInstance
(
context
).
initializeWith
(
this
,
filter
);
}
public
static
<
T
extends
RealmModel
>
Flowable
<
T
>
copyToRealmOrUpdate
(
Realm
realm
,
T
objectToCopy
)
{
return
Flowable
.
defer
(()
->
{
realm
.
beginTransaction
();
try
{
T
object
=
realm
.
copyToRealmOrUpdate
(
objectToCopy
);
realm
.
commitTransaction
();
return
Flowable
.
just
(
object
);
}
catch
(
Throwable
e
)
{
if
(
realm
.
isInTransaction
())
{
realm
.
cancelTransaction
();
}
else
{
RealmLog
.
warn
(
"Could not cancel transaction, not currently in a transaction."
);
}
throw
e
;
}
});
}
public
interface
Transaction
<
T
>
{
T
execute
(
Realm
realm
)
throws
JSONException
;
}
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/RealmListObserver.java
View file @
5bbd3f7f
package
chat
.
rocket
.
persistence
.
realm
;
import
java.util.List
;
import
io.realm.Realm
;
import
io.realm.RealmChangeListener
;
import
io.realm.RealmObject
;
import
io.realm.RealmResults
;
import
java.util.List
;
public
class
RealmListObserver
<
T
extends
RealmObject
>
extends
AbstractRealmResultsObserver
<
T
>
{
private
final
Query
<
T
>
query
;
private
OnUpdateListener
<
T
>
onUpdateListener
;
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/RealmStore.java
View file @
5bbd3f7f
package
chat
.
rocket
.
persistence
.
realm
;
import
io.realm.Realm
;
import
io.realm.RealmConfiguration
;
import
java.util.HashMap
;
import
chat.rocket.persistence.realm.modules.RocketChatLibraryModule
;
import
chat.rocket.persistence.realm.modules.RocketChatServerModule
;
import
io.realm.Realm
;
import
io.realm.RealmConfiguration
;
public
class
RealmStore
{
public
static
HashMap
<
String
,
RealmConfiguration
>
sStore
=
new
HashMap
<>();
...
...
@@ -15,9 +15,7 @@ public class RealmStore {
.
name
(
name
+
".realm"
)
.
modules
(
new
RocketChatLibraryModule
())
.
migration
(
new
Migration
())
.
schemaVersion
(
5
)
// Just in case
.
deleteRealmIfMigrationNeeded
()
.
schemaVersion
(
6
)
.
build
();
}
...
...
@@ -49,7 +47,7 @@ public class RealmStore {
sStore
.
put
(
name
,
new
RealmConfiguration
.
Builder
()
.
name
(
name
+
".realm"
)
.
modules
(
new
RocketChatServerModule
())
.
deleteRealmIfMigrationNeeded
().
build
());
.
build
());
}
return
new
RealmHelper
(
sStore
.
get
(
name
));
}
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/RocketChatPersistenceRealm.java
View file @
5bbd3f7f
package
chat
.
rocket
.
persistence
.
realm
;
import
android.content.Context
;
import
io.realm.Realm
;
import
io.realm.RealmConfiguration
;
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/models/RealmBasedServerInfo.java
View file @
5bbd3f7f
...
...
@@ -2,17 +2,18 @@ package chat.rocket.persistence.realm.models;
import
android.support.annotation.Nullable
;
import
android.text.TextUtils
;
import
io.realm.Realm
;
import
io.realm.RealmObject
;
import
io.realm.annotations.PrimaryKey
;
import
org.json.JSONObject
;
import
java.util.ArrayList
;
import
java.util.List
;
import
chat.rocket.core.models.ServerInfo
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.persistence.realm.RealmStore
;
import
io.realm.Realm
;
import
io.realm.RealmObject
;
import
io.realm.annotations.PrimaryKey
;
/**
* Backend implementation to store ServerInfo.
...
...
@@ -41,7 +42,7 @@ public class RealmBasedServerInfo extends RealmObject {
.
build
();
}
public
static
Realm
getRealm
()
{
public
static
Realm
get
Server
Realm
()
{
return
RealmStore
.
getRealm
(
DB_NAME
);
}
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/models/ddp/RealmEmail.java
View file @
5bbd3f7f
package
chat
.
rocket
.
persistence
.
realm
.
models
.
ddp
;
import
chat.rocket.core.models.Email
;
import
io.realm.RealmObject
;
import
io.realm.annotations.PrimaryKey
;
import
chat.rocket.core.models.Email
;
/**
* Login-RealmUser's email.
*/
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/models/ddp/RealmMessage.java
View file @
5bbd3f7f
package
chat
.
rocket
.
persistence
.
realm
.
models
.
ddp
;
import
io.realm.RealmObject
;
import
io.realm.annotations.PrimaryKey
;
import
org.json.JSONArray
;
import
org.json.JSONException
;
import
org.json.JSONObject
;
...
...
@@ -10,6 +8,7 @@ import java.util.ArrayList;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
chat.rocket.core.JsonConstants
;
import
chat.rocket.core.SyncState
;
import
chat.rocket.core.models.Attachment
;
...
...
@@ -21,6 +20,8 @@ import chat.rocket.core.models.WebContent;
import
chat.rocket.core.models.WebContentHeaders
;
import
chat.rocket.core.models.WebContentMeta
;
import
chat.rocket.core.models.WebContentParsedUrl
;
import
io.realm.RealmObject
;
import
io.realm.annotations.PrimaryKey
;
/**
* RealmMessage.
...
...
@@ -191,7 +192,7 @@ public class RealmMessage extends RealmObject {
.
setRoomId
(
rid
)
.
setSyncState
(
syncstate
)
.
setTimestamp
(
ts
)
.
setMessage
(
msg
)
.
setMessage
(
msg
==
null
?
""
:
msg
)
.
setUser
(
u
!=
null
?
u
.
asUser
()
:
null
)
.
setGroupable
(
groupable
)
.
setAlias
(
alias
)
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/models/ddp/RealmMeteorLoginServiceConfiguration.java
View file @
5bbd3f7f
package
chat
.
rocket
.
persistence
.
realm
.
models
.
ddp
;
import
chat.rocket.core.models.LoginServiceConfiguration
;
import
io.realm.RealmObject
;
import
io.realm.annotations.PrimaryKey
;
import
chat.rocket.core.models.LoginServiceConfiguration
;
/**
* subscription model for "meteor_accounts_loginServiceConfiguration".
*/
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/models/ddp/RealmPermission.java
View file @
5bbd3f7f
package
chat
.
rocket
.
persistence
.
realm
.
models
.
ddp
;
import
io.realm.RealmList
;
import
io.realm.RealmObject
;
import
io.realm.annotations.PrimaryKey
;
import
org.json.JSONArray
;
import
org.json.JSONException
;
import
org.json.JSONObject
;
import
java.util.ArrayList
;
import
java.util.List
;
import
chat.rocket.core.models.Permission
;
import
chat.rocket.core.models.Role
;
import
io.realm.RealmList
;
import
io.realm.RealmObject
;
import
io.realm.annotations.PrimaryKey
;
public
class
RealmPermission
extends
RealmObject
{
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/models/ddp/RealmPreferences.java
View file @
5bbd3f7f
package
chat
.
rocket
.
persistence
.
realm
.
models
.
ddp
;
import
chat.rocket.core.models.Preferences
;
import
io.realm.RealmObject
;
import
io.realm.annotations.PrimaryKey
;
import
chat.rocket.core.models.Preferences
;
@SuppressWarnings
({
"PMD.ShortVariable"
})
public
class
RealmPreferences
extends
RealmObject
{
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/models/ddp/RealmPublicSetting.java
View file @
5bbd3f7f
package
chat
.
rocket
.
persistence
.
realm
.
models
.
ddp
;
import
android.support.annotation.Nullable
;
import
io.realm.RealmObject
;
import
io.realm.annotations.PrimaryKey
;
import
org.json.JSONException
;
import
org.json.JSONObject
;
import
chat.rocket.core.JsonConstants
;
import
chat.rocket.core.models.PublicSetting
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
io.realm.RealmObject
;
import
io.realm.annotations.PrimaryKey
;
/**
* public setting model.
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/models/ddp/RealmRole.java
View file @
5bbd3f7f
package
chat
.
rocket
.
persistence
.
realm
.
models
.
ddp
;
import
io.realm.RealmObject
;
import
io.realm.annotations.PrimaryKey
;
import
org.json.JSONException
;
import
org.json.JSONObject
;
import
chat.rocket.core.models.Role
;
import
io.realm.RealmObject
;
import
io.realm.annotations.PrimaryKey
;
public
class
RealmRole
extends
RealmObject
{
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/models/ddp/RealmRoom.java
View file @
5bbd3f7f
package
chat
.
rocket
.
persistence
.
realm
.
models
.
ddp
;
import
io.realm.RealmObject
;
import
io.realm.annotations.PrimaryKey
;
import
org.json.JSONException
;
import
org.json.JSONObject
;
import
chat.rocket.core.JsonConstants
;
import
chat.rocket.core.models.Room
;
import
io.realm.RealmObject
;
import
io.realm.annotations.PrimaryKey
;
/**
* Chat Room(Subscription).
...
...
@@ -142,7 +142,7 @@ public class RealmRoom extends RealmObject {
return
Room
.
builder
()
.
setId
(
_id
)
.
setRoomId
(
rid
)
.
setName
(
name
)
.
setName
(
name
==
null
?
""
:
name
)
.
setType
(
t
)
.
setOpen
(
open
)
.
setAlert
(
alert
)
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/models/ddp/RealmRoomRole.java
View file @
5bbd3f7f
package
chat
.
rocket
.
persistence
.
realm
.
models
.
ddp
;
import
io.realm.RealmList
;
import
io.realm.RealmObject
;
import
io.realm.annotations.PrimaryKey
;
import
org.json.JSONArray
;
import
org.json.JSONException
;
import
org.json.JSONObject
;
import
java.util.ArrayList
;
import
java.util.List
;
import
chat.rocket.core.models.Role
;
import
chat.rocket.core.models.RoomRole
;
import
io.realm.RealmList
;
import
io.realm.RealmObject
;
import
io.realm.annotations.PrimaryKey
;
public
class
RealmRoomRole
extends
RealmObject
{
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/models/ddp/RealmSettings.java
View file @
5bbd3f7f
package
chat
.
rocket
.
persistence
.
realm
.
models
.
ddp
;
import
chat.rocket.core.models.Settings
;
import
io.realm.RealmObject
;
import
io.realm.annotations.PrimaryKey
;
import
chat.rocket.core.models.Settings
;
@SuppressWarnings
({
"PMD.ShortVariable"
})
public
class
RealmSettings
extends
RealmObject
{
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/models/ddp/RealmSpotlightRoom.java
View file @
5bbd3f7f
package
chat
.
rocket
.
persistence
.
realm
.
models
.
ddp
;
import
chat.rocket.core.models.SpotlightRoom
;
import
io.realm.RealmObject
;
import
io.realm.annotations.PrimaryKey
;
import
chat.rocket.core.models.SpotlightRoom
;
public
class
RealmSpotlightRoom
extends
RealmObject
{
public
interface
Columns
{
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/models/ddp/RealmSpotlightUser.java
View file @
5bbd3f7f
package
chat
.
rocket
.
persistence
.
realm
.
models
.
ddp
;
import
chat.rocket.core.models.SpotlightUser
;
import
io.realm.RealmObject
;
import
io.realm.annotations.PrimaryKey
;
import
chat.rocket.core.models.SpotlightUser
;
public
class
RealmSpotlightUser
extends
RealmObject
{
public
interface
Columns
{
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/models/internal/GcmPushRegistration.java
View file @
5bbd3f7f
package
chat
.
rocket
.
persistence
.
realm
.
models
.
internal
;
import
io.realm.Realm
;
import
io.realm.RealmObject
;
import
io.realm.RealmQuery
;
import
io.realm.annotations.PrimaryKey
;
import
org.json.JSONException
;
import
org.json.JSONObject
;
import
chat.rocket.core.SyncState
;
import
io.realm.Realm
;
import
io.realm.RealmObject
;
import
io.realm.RealmQuery
;
import
io.realm.annotations.PrimaryKey
;
/**
* just stores gcm registration status.
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/models/internal/LoadMessageProcedure.java
View file @
5bbd3f7f
package
chat
.
rocket
.
persistence
.
realm
.
models
.
internal
;
import
chat.rocket.core.models.RoomHistoryState
;
import
io.realm.RealmObject
;
import
io.realm.annotations.PrimaryKey
;
import
chat.rocket.core.models.RoomHistoryState
;
/**
* Load messages in the room.
*/
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/models/internal/MethodCall.java
View file @
5bbd3f7f
package
chat
.
rocket
.
persistence
.
realm
.
models
.
internal
;
import
android.text.TextUtils
;
import
io.realm.RealmObject
;
import
io.realm.annotations.PrimaryKey
;
import
org.json.JSONObject
;
import
java.util.HashMap
;
import
java.util.UUID
;
import
bolts.Task
;
import
bolts.TaskCompletionSource
;
import
chat.rocket.android.log.RCLog
;
...
...
@@ -14,6 +14,8 @@ import chat.rocket.core.SyncState;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.persistence.realm.RealmObjectObserver
;
import
chat.rocket.persistence.realm.helpers.LogcatIfError
;
import
io.realm.RealmObject
;
import
io.realm.annotations.PrimaryKey
;
public
class
MethodCall
extends
RealmObject
{
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/models/internal/RealmSession.java
View file @
5bbd3f7f
package
chat
.
rocket
.
persistence
.
realm
.
models
.
internal
;
import
android.text.TextUtils
;
import
io.realm.Realm
;
import
io.realm.RealmObject
;
import
io.realm.RealmQuery
;
import
io.realm.annotations.PrimaryKey
;
import
org.json.JSONObject
;
import
chat.rocket.core.models.Session
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.persistence.realm.helpers.LogcatIfError
;
import
hugo.weaving.DebugLog
;
import
io.realm.Realm
;
import
io.realm.RealmObject
;
import
io.realm.RealmQuery
;
import
io.realm.annotations.PrimaryKey
;
/**
* Login session info.
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/modules/RocketChatServerModule.java
View file @
5bbd3f7f
package
chat
.
rocket
.
persistence
.
realm
.
modules
;
import
io.realm.annotations.RealmModule
;
import
chat.rocket.persistence.realm.models.RealmBasedServerInfo
;
import
io.realm.annotations.RealmModule
;
@RealmModule
(
library
=
true
,
classes
=
{
RealmBasedServerInfo
.
class
})
public
class
RocketChatServerModule
{
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/repositories/RealmLoginServiceConfigurationRepository.java
View file @
5bbd3f7f
...
...
@@ -2,19 +2,20 @@ package chat.rocket.persistence.realm.repositories;
import
android.os.Looper
;
import
android.support.v4.util.Pair
;
import
com.hadisatrio.optional.Optional
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.realm.RealmResults
;
import
java.util.ArrayList
;
import
java.util.List
;
import
chat.rocket.core.models.LoginServiceConfiguration
;
import
chat.rocket.core.repositories.LoginServiceConfigurationRepository
;
import
chat.rocket.persistence.realm.RealmStore
;
import
chat.rocket.persistence.realm.models.ddp.RealmMeteorLoginServiceConfiguration
;
import
hu.akarnokd.rxjava.interop.RxJavaInterop
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.realm.RealmResults
;
public
class
RealmLoginServiceConfigurationRepository
extends
RealmRepository
implements
LoginServiceConfigurationRepository
{
...
...
@@ -34,11 +35,10 @@ public class RealmLoginServiceConfigurationRepository extends RealmRepository
return
Flowable
.
empty
();
}
return
RxJavaInterop
.
toV2Flowable
(
pair
.
first
.
where
(
RealmMeteorLoginServiceConfiguration
.
class
)
return
pair
.
first
.
where
(
RealmMeteorLoginServiceConfiguration
.
class
)
.
equalTo
(
RealmMeteorLoginServiceConfiguration
.
SERVICE
,
serviceName
)
.
findAll
()
.<
RealmResults
<
RealmMeteorLoginServiceConfiguration
>>
as
Observable
()
);
.<
RealmResults
<
RealmMeteorLoginServiceConfiguration
>>
as
Flowable
(
);
},
pair
->
close
(
pair
.
first
,
pair
.
second
)
)
...
...
@@ -57,10 +57,9 @@ public class RealmLoginServiceConfigurationRepository extends RealmRepository
return
Flowable
.
empty
();
}
return
RxJavaInterop
.
toV2Flowable
(
pair
.
first
.
where
(
RealmMeteorLoginServiceConfiguration
.
class
)
return
pair
.
first
.
where
(
RealmMeteorLoginServiceConfiguration
.
class
)
.
findAll
()
.
as
Observable
()
);
.
as
Flowable
(
);
},
pair
->
close
(
pair
.
first
,
pair
.
second
)
)
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/repositories/RealmMessageRepository.java
View file @
5bbd3f7f
...
...
@@ -5,24 +5,24 @@ import android.support.v4.util.Pair;
import
com.hadisatrio.optional.Optional
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.realm.Realm
;
import
io.realm.RealmResults
;
import
io.realm.Sort
;
import
java.util.ArrayList
;
import
java.util.List
;
import
chat.rocket.core.SyncState
;
import
chat.rocket.core.models.Message
;
import
chat.rocket.core.models.Room
;
import
chat.rocket.core.models.User
;
import
chat.rocket.core.repositories.MessageRepository
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.persistence.realm.RealmStore
;
import
chat.rocket.persistence.realm.models.ddp.RealmMessage
;
import
chat.rocket.persistence.realm.models.ddp.RealmUser
;
import
hu.akarnokd.rxjava.interop.RxJavaInterop
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.realm.Realm
;
import
io.realm.RealmResults
;
import
io.realm.Sort
;
public
class
RealmMessageRepository
extends
RealmRepository
implements
MessageRepository
{
...
...
@@ -41,11 +41,10 @@ public class RealmMessageRepository extends RealmRepository implements MessageRe
return
Flowable
.
empty
();
}
return
RxJavaInterop
.
toV2Flowable
(
pair
.
first
.
where
(
RealmMessage
.
class
)
return
pair
.
first
.
where
(
RealmMessage
.
class
)
.
equalTo
(
RealmMessage
.
ID
,
messageId
)
.
findAll
()
.<
RealmResults
<
RealmMessage
>>
as
Observable
()
);
.<
RealmResults
<
RealmMessage
>>
as
Flowable
(
);
},
pair
->
close
(
pair
.
first
,
pair
.
second
)
)
...
...
@@ -90,16 +89,12 @@ public class RealmMessageRepository extends RealmRepository implements MessageRe
}
realmMessage
.
setUser
(
realmUser
);
realm
.
beginTransaction
()
;
final
RealmMessage
messageToSave
=
realmMessage
;
return
RxJavaInterop
.
toV2Flowable
(
realm
.
copyToRealmOrUpdate
(
realmMessage
)
.
asObservable
())
return
RealmHelper
.
copyToRealmOrUpdate
(
realm
,
messageToSave
)
.
filter
(
it
->
it
.
isLoaded
()
&&
it
.
isValid
())
.
firstElement
()
.
doOnSuccess
(
it
->
realm
.
commitTransaction
())
.
doOnError
(
throwable
->
realm
.
cancelTransaction
())
.
first
(
new
RealmMessage
())
.
doOnEvent
((
realmObject
,
throwable
)
->
close
(
realm
,
looper
))
.
toSingle
()
.
map
(
realmObject
->
true
);
});
}
...
...
@@ -116,10 +111,10 @@ public class RealmMessageRepository extends RealmRepository implements MessageRe
realm
.
beginTransaction
();
return
RxJavaInterop
.
toV2Flowable
(
realm
.
where
(
RealmMessage
.
class
)
return
realm
.
where
(
RealmMessage
.
class
)
.
equalTo
(
RealmMessage
.
ID
,
message
.
getId
())
.
findAll
()
.<
RealmResults
<
RealmMessage
>>
as
Observable
()
)
.<
RealmResults
<
RealmMessage
>>
as
Flowable
(
)
.
filter
(
realmObject
->
realmObject
.
isLoaded
()
&&
realmObject
.
isValid
())
.
firstElement
()
.
toSingle
()
...
...
@@ -144,11 +139,13 @@ public class RealmMessageRepository extends RealmRepository implements MessageRe
return
Flowable
.
empty
();
}
return
RxJavaInterop
.
toV2Flowable
(
pair
.
first
.
where
(
RealmMessage
.
class
)
return
pair
.
first
.
where
(
RealmMessage
.
class
)
.
notEqualTo
(
RealmMessage
.
SYNC_STATE
,
SyncState
.
DELETE_NOT_SYNCED
)
.
notEqualTo
(
RealmMessage
.
SYNC_STATE
,
SyncState
.
DELETING
)
.
equalTo
(
RealmMessage
.
ROOM_ID
,
room
.
getRoomId
())
.
isNotNull
(
RealmMessage
.
USER
)
.
findAllSorted
(
RealmMessage
.
TIMESTAMP
,
Sort
.
DESCENDING
)
.
as
Observable
()
);
.
as
Flowable
(
);
},
pair
->
close
(
pair
.
first
,
pair
.
second
)
)
...
...
@@ -167,12 +164,12 @@ public class RealmMessageRepository extends RealmRepository implements MessageRe
return
Flowable
.
empty
();
}
return
RxJavaInterop
.
toV2Flowable
(
pair
.
first
.
where
(
RealmMessage
.
class
)
return
pair
.
first
.
where
(
RealmMessage
.
class
)
.
equalTo
(
RealmMessage
.
ROOM_ID
,
room
.
getId
())
.
greaterThanOrEqualTo
(
RealmMessage
.
TIMESTAMP
,
room
.
getLastSeen
())
.
notEqualTo
(
RealmMessage
.
USER_ID
,
user
.
getId
())
.
findAll
()
.
as
Observable
()
);
.
as
Flowable
(
);
},
pair
->
close
(
pair
.
first
,
pair
.
second
)
)
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/repositories/RealmPermissionRepository.java
View file @
5bbd3f7f
...
...
@@ -2,17 +2,17 @@ package chat.rocket.persistence.realm.repositories;
import
android.os.Looper
;
import
android.support.v4.util.Pair
;
import
com.hadisatrio.optional.Optional
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.realm.RealmResults
;
import
chat.rocket.core.models.Permission
;
import
chat.rocket.core.repositories.PermissionRepository
;
import
chat.rocket.persistence.realm.RealmStore
;
import
chat.rocket.persistence.realm.models.ddp.RealmPermission
;
import
hu.akarnokd.rxjava.interop.RxJavaInterop
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.realm.RealmResults
;
public
class
RealmPermissionRepository
extends
RealmRepository
implements
PermissionRepository
{
...
...
@@ -30,11 +30,10 @@ public class RealmPermissionRepository extends RealmRepository implements Permis
if
(
pair
.
first
==
null
)
{
return
Flowable
.
empty
();
}
return
RxJavaInterop
.
toV2Flowable
(
pair
.
first
.
where
(
RealmPermission
.
class
)
return
pair
.
first
.
where
(
RealmPermission
.
class
)
.
equalTo
(
RealmPermission
.
Columns
.
ID
,
id
)
.
findAll
()
.<
RealmResults
<
RealmPermission
>>
as
Observable
()
);
.<
RealmResults
<
RealmPermission
>>
as
Flowable
(
);
},
pair
->
close
(
pair
.
first
,
pair
.
second
)
)
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/repositories/RealmPublicSettingRepository.java
View file @
5bbd3f7f
...
...
@@ -2,17 +2,17 @@ package chat.rocket.persistence.realm.repositories;
import
android.os.Looper
;
import
android.support.v4.util.Pair
;
import
com.hadisatrio.optional.Optional
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.realm.RealmResults
;
import
chat.rocket.core.models.PublicSetting
;
import
chat.rocket.core.repositories.PublicSettingRepository
;
import
chat.rocket.persistence.realm.RealmStore
;
import
chat.rocket.persistence.realm.models.ddp.RealmPublicSetting
;
import
hu.akarnokd.rxjava.interop.RxJavaInterop
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.realm.RealmResults
;
public
class
RealmPublicSettingRepository
extends
RealmRepository
implements
PublicSettingRepository
{
...
...
@@ -31,11 +31,10 @@ public class RealmPublicSettingRepository extends RealmRepository
if
(
pair
.
first
==
null
)
{
return
Flowable
.
empty
();
}
return
RxJavaInterop
.
toV2Flowable
(
pair
.
first
.
where
(
RealmPublicSetting
.
class
)
return
pair
.
first
.
where
(
RealmPublicSetting
.
class
)
.
equalTo
(
RealmPublicSetting
.
ID
,
id
)
.
findAll
()
.<
RealmResults
<
RealmPublicSetting
>>
as
Observable
()
);
.<
RealmResults
<
RealmPublicSetting
>>
as
Flowable
(
);
},
pair
->
close
(
pair
.
first
,
pair
.
second
)
)
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/repositories/RealmRepository.java
View file @
5bbd3f7f
...
...
@@ -2,12 +2,13 @@ package chat.rocket.persistence.realm.repositories;
import
android.os.Handler
;
import
android.os.Looper
;
import
java.util.List
;
import
io.realm.Realm
;
import
io.realm.RealmObject
;
import
io.realm.RealmResults
;
import
java.util.List
;
public
class
RealmRepository
{
protected
void
close
(
Realm
realm
,
Looper
looper
)
{
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/repositories/RealmRoomRepository.java
View file @
5bbd3f7f
...
...
@@ -2,25 +2,27 @@ package chat.rocket.persistence.realm.repositories;
import
android.os.Looper
;
import
android.support.v4.util.Pair
;
import
com.hadisatrio.optional.Optional
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.realm.Case
;
import
io.realm.Realm
;
import
io.realm.RealmResults
;
import
io.realm.Sort
;
import
java.util.ArrayList
;
import
java.util.List
;
import
chat.rocket.core.SortDirection
;
import
chat.rocket.core.models.Room
;
import
chat.rocket.core.models.RoomHistoryState
;
import
chat.rocket.core.repositories.RoomRepository
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.persistence.realm.RealmStore
;
import
chat.rocket.persistence.realm.models.ddp.RealmRoom
;
import
chat.rocket.persistence.realm.models.internal.LoadMessageProcedure
;
import
hu.akarnokd.rxjava.interop.RxJavaInterop
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.realm.Case
;
import
io.realm.Realm
;
import
io.realm.RealmResults
;
import
io.realm.Sort
;
public
class
RealmRoomRepository
extends
RealmRepository
implements
RoomRepository
{
...
...
@@ -39,10 +41,9 @@ public class RealmRoomRepository extends RealmRepository implements RoomReposito
return
Flowable
.
empty
();
}
return
RxJavaInterop
.
toV2Flowable
(
pair
.
first
.
where
(
RealmRoom
.
class
)
return
pair
.
first
.
where
(
RealmRoom
.
class
)
.
findAll
()
.
as
Observable
()
);
.
as
Flowable
(
);
},
pair
->
close
(
pair
.
first
,
pair
.
second
)
)
...
...
@@ -69,13 +70,11 @@ public class RealmRoomRepository extends RealmRepository implements RoomReposito
return
Flowable
.
just
(
Optional
.<
RealmRoom
>
absent
());
}
return
RxJavaInterop
.
toV2Flowable
(
realmRoom
.<
RealmRoom
>
asObservable
()
return
realmRoom
.<
RealmRoom
>
asFlowable
()
.
filter
(
roomSubscription
->
roomSubscription
.
isLoaded
()
&&
roomSubscription
.
isValid
())
.
map
(
Optional:
:
of
)
)
;
.
map
(
Optional:
:
of
);
},
pair
->
close
(
pair
.
first
,
pair
.
second
)
)
...
...
@@ -106,12 +105,10 @@ public class RealmRoomRepository extends RealmRepository implements RoomReposito
return
Flowable
.
just
(
Optional
.<
LoadMessageProcedure
>
absent
());
}
return
RxJavaInterop
.
toV2Flowable
(
messageProcedure
.<
LoadMessageProcedure
>
asObservable
()
return
messageProcedure
.<
LoadMessageProcedure
>
asFlowable
()
.
filter
(
loadMessageProcedure
->
loadMessageProcedure
.
isLoaded
()
&&
loadMessageProcedure
.
isValid
())
.
map
(
Optional:
:
of
)
)
;
.
map
(
Optional:
:
of
);
},
pair
->
close
(
pair
.
first
,
pair
.
second
)
)
...
...
@@ -142,14 +139,9 @@ public class RealmRoomRepository extends RealmRepository implements RoomReposito
loadMessage
.
setHasNext
(!
roomHistoryState
.
isComplete
());
loadMessage
.
setTimestamp
(
roomHistoryState
.
getTimestamp
());
realm
.
beginTransaction
();
return
RxJavaInterop
.
toV2Flowable
(
realm
.
copyToRealmOrUpdate
(
loadMessage
)
.
asObservable
())
return
RealmHelper
.
copyToRealmOrUpdate
(
realm
,
loadMessage
)
.
filter
(
realmObject
->
realmObject
.
isLoaded
()
&&
realmObject
.
isValid
())
.
firstElement
()
.
doOnSuccess
(
it
->
realm
.
commitTransaction
())
.
doOnError
(
throwable
->
realm
.
cancelTransaction
())
.
doOnEvent
((
realmObject
,
throwable
)
->
close
(
realm
,
looper
))
.
toSingle
()
.
map
(
realmObject
->
true
);
...
...
@@ -164,8 +156,7 @@ public class RealmRoomRepository extends RealmRepository implements RoomReposito
if
(
pair
.
first
==
null
)
{
return
Flowable
.
empty
();
}
return
RxJavaInterop
.
toV2Flowable
(
pair
.
first
.
where
(
RealmRoom
.
class
)
return
pair
.
first
.
where
(
RealmRoom
.
class
)
.
like
(
RealmRoom
.
NAME
,
"*"
+
name
+
"*"
,
Case
.
INSENSITIVE
)
.
beginGroup
()
.
equalTo
(
RealmRoom
.
TYPE
,
RealmRoom
.
TYPE_CHANNEL
)
...
...
@@ -174,7 +165,7 @@ public class RealmRoomRepository extends RealmRepository implements RoomReposito
.
endGroup
()
.
findAllSorted
(
RealmRoom
.
NAME
,
direction
.
equals
(
SortDirection
.
ASC
)
?
Sort
.
ASCENDING
:
Sort
.
DESCENDING
)
.
as
Observable
()
);
.
as
Flowable
(
);
},
pair
->
close
(
pair
.
first
,
pair
.
second
)
)
...
...
@@ -192,15 +183,14 @@ public class RealmRoomRepository extends RealmRepository implements RoomReposito
if
(
pair
.
first
==
null
)
{
return
Flowable
.
empty
();
}
return
RxJavaInterop
.
toV2Flowable
(
pair
.
first
.
where
(
RealmRoom
.
class
)
return
pair
.
first
.
where
(
RealmRoom
.
class
)
.
beginGroup
()
.
equalTo
(
RealmRoom
.
TYPE
,
RealmRoom
.
TYPE_CHANNEL
)
.
or
()
.
equalTo
(
RealmRoom
.
TYPE
,
RealmRoom
.
TYPE_PRIVATE
)
.
endGroup
()
.
findAllSorted
(
RealmRoom
.
LAST_SEEN
,
Sort
.
ASCENDING
)
.
as
Observable
()
);
.
as
Flowable
(
);
},
pair
->
close
(
pair
.
first
,
pair
.
second
)
)
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/repositories/RealmRoomRoleRepository.java
View file @
5bbd3f7f
...
...
@@ -2,11 +2,8 @@ package chat.rocket.persistence.realm.repositories;
import
android.os.Looper
;
import
android.support.v4.util.Pair
;
import
com.hadisatrio.optional.Optional
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.realm.RealmResults
;
import
chat.rocket.core.models.Room
;
import
chat.rocket.core.models.RoomRole
;
...
...
@@ -15,7 +12,10 @@ import chat.rocket.core.repositories.RoomRoleRepository;
import
chat.rocket.persistence.realm.RealmStore
;
import
chat.rocket.persistence.realm.models.ddp.RealmRoomRole
;
import
chat.rocket.persistence.realm.models.ddp.RealmUser
;
import
hu.akarnokd.rxjava.interop.RxJavaInterop
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.realm.RealmResults
;
public
class
RealmRoomRoleRepository
extends
RealmRepository
implements
RoomRoleRepository
{
...
...
@@ -33,12 +33,11 @@ public class RealmRoomRoleRepository extends RealmRepository implements RoomRole
if
(
pair
.
first
==
null
)
{
return
Flowable
.
empty
();
}
return
RxJavaInterop
.
toV2Flowable
(
pair
.
first
.
where
(
RealmRoomRole
.
class
)
return
pair
.
first
.
where
(
RealmRoomRole
.
class
)
.
equalTo
(
RealmRoomRole
.
Columns
.
ROOM_ID
,
room
.
getId
())
.
equalTo
(
RealmRoomRole
.
Columns
.
USER
+
"."
+
RealmUser
.
ID
,
user
.
getId
())
.
findAll
()
.<
RealmResults
<
RealmRoomRole
>>
as
Observable
()
);
.<
RealmResults
<
RealmRoomRole
>>
as
Flowable
(
);
},
pair
->
close
(
pair
.
first
,
pair
.
second
)
)
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/repositories/RealmServerInfoRepository.java
View file @
5bbd3f7f
...
...
@@ -2,21 +2,21 @@ package chat.rocket.persistence.realm.repositories;
import
android.os.Looper
;
import
android.support.v4.util.Pair
;
import
com.hadisatrio.optional.Optional
;
import
io.reactivex.Flowable
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
chat.rocket.core.models.ServerInfo
;
import
chat.rocket.core.repositories.ServerInfoRepository
;
import
chat.rocket.persistence.realm.models.RealmBasedServerInfo
;
import
hu.akarnokd.rxjava.interop.RxJavaInterop
;
import
io.reactivex.Flowable
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
public
class
RealmServerInfoRepository
extends
RealmRepository
implements
ServerInfoRepository
{
@Override
public
Flowable
<
Optional
<
ServerInfo
>>
getByHostname
(
String
hostname
)
{
return
Flowable
.
defer
(()
->
Flowable
.
using
(
()
->
new
Pair
<>(
RealmBasedServerInfo
.
getRealm
(),
Looper
.
myLooper
()),
()
->
new
Pair
<>(
RealmBasedServerInfo
.
get
Server
Realm
(),
Looper
.
myLooper
()),
pair
->
{
RealmBasedServerInfo
info
=
pair
.
first
.
where
(
RealmBasedServerInfo
.
class
)
.
equalTo
(
RealmBasedServerInfo
.
ColumnName
.
HOSTNAME
,
hostname
)
...
...
@@ -26,10 +26,9 @@ public class RealmServerInfoRepository extends RealmRepository implements Server
return
Flowable
.
just
(
Optional
.<
RealmBasedServerInfo
>
absent
());
}
return
RxJavaInterop
.
toV2Flowable
(
info
.<
RealmBasedServerInfo
>
asObservable
()
return
info
.<
RealmBasedServerInfo
>
asFlowable
()
.
filter
(
it
->
it
.
isLoaded
()
&&
it
.
isValid
())
.
map
(
Optional:
:
of
)
)
;
.
map
(
Optional:
:
of
);
},
pair
->
close
(
pair
.
first
,
pair
.
second
)
)
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/repositories/RealmSessionRepository.java
View file @
5bbd3f7f
...
...
@@ -2,17 +2,18 @@ package chat.rocket.persistence.realm.repositories;
import
android.os.Looper
;
import
android.support.v4.util.Pair
;
import
com.hadisatrio.optional.Optional
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.realm.Realm
;
import
chat.rocket.core.models.Session
;
import
chat.rocket.core.repositories.SessionRepository
;
import
chat.rocket.persistence.realm.RealmHelper
;
import
chat.rocket.persistence.realm.RealmStore
;
import
chat.rocket.persistence.realm.models.internal.RealmSession
;
import
hu.akarnokd.rxjava.interop.RxJavaInterop
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.realm.Realm
;
public
class
RealmSessionRepository
extends
RealmRepository
implements
SessionRepository
{
...
...
@@ -31,11 +32,10 @@ public class RealmSessionRepository extends RealmRepository implements SessionRe
return
Flowable
.
empty
();
}
return
RxJavaInterop
.
toV2Flowable
(
pair
.
first
.
where
(
RealmSession
.
class
)
return
pair
.
first
.
where
(
RealmSession
.
class
)
.
equalTo
(
RealmSession
.
ID
,
id
)
.
findAll
()
.<
RealmSession
>
as
Observable
()
);
.<
RealmSession
>
as
Flowable
(
);
},
pair
->
close
(
pair
.
first
,
pair
.
second
)
)
...
...
@@ -45,7 +45,7 @@ public class RealmSessionRepository extends RealmRepository implements SessionRe
if
(
realmSessions
.
size
()
==
0
)
{
return
Optional
.
absent
();
}
return
Optional
.
of
(
realmSessions
.
get
(
0
).
asSession
());
return
Optional
.
of
(
realmSessions
.
get
(
0
).
asSession
());
}));
}
...
...
@@ -74,14 +74,9 @@ public class RealmSessionRepository extends RealmRepository implements SessionRe
realmSession
.
setTokenVerified
(
session
.
isTokenVerified
());
realmSession
.
setError
(
session
.
getError
());
realm
.
beginTransaction
();
return
RxJavaInterop
.
toV2Flowable
(
realm
.
copyToRealmOrUpdate
(
realmSession
)
.
asObservable
())
return
RealmHelper
.
copyToRealmOrUpdate
(
realm
,
realmSession
)
.
filter
(
it
->
it
!=
null
&&
it
.
isLoaded
()
&&
it
.
isValid
())
.
firstElement
()
.
doOnSuccess
(
it
->
realm
.
commitTransaction
())
.
doOnError
(
throwable
->
realm
.
cancelTransaction
())
.
doOnEvent
((
realmObject
,
throwable
)
->
close
(
realm
,
looper
))
.
toSingle
()
.
map
(
realmObject
->
true
);
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/repositories/RealmSpotlightRepository.kt
View file @
5bbd3f7f
package
chat.rocket.persistence.realm.repositories
import
android.os.Looper
import
android.support.v4.util.Pair
import
chat.rocket.core.models.Spotlight
import
chat.rocket.core.repositories.SpotlightRepository
import
chat.rocket.persistence.realm.RealmStore
import
chat.rocket.persistence.realm.models.ddp.RealmSpotlight
import
chat.rocket.persistence.realm.models.ddp.RealmSpotlight.Columns
import
hu.akarnokd.rxjava.interop.RxJavaInterop
import
io.reactivex.Flowable
import
io.reactivex.android.schedulers.AndroidSchedulers
import
io.realm.Realm
import
io.realm.RealmResults
import
io.realm.Sort
import
java.util.
ArrayList
import
java.util.
*
class
RealmSpotlightRepository
(
private
val
hostname
:
String
)
:
RealmRepository
(),
SpotlightRepository
{
...
...
@@ -25,9 +23,9 @@ class RealmSpotlightRepository(private val hostname: String) : RealmRepository()
return
@using
Flowable
.
empty
()
}
return
@using
RxJavaInterop
.
toV2Flowable
<
RealmResults
<
RealmSpotlight
>>(
pair
.
first
.
where
(
RealmSpotlight
::
class
.
java
)
.
findAllSorted
(
Columns
.
TYPE
,
Sort
.
DESCENDING
)
.
asObservable
()
)
return
@using
pair
.
first
.
where
(
RealmSpotlight
::
class
.
java
)
.
findAllSorted
(
Columns
.
TYPE
,
Sort
.
DESCENDING
)
.
asFlowable
(
)
})
{
pair
->
close
(
pair
.
first
,
pair
.
second
)
}
.
unsubscribeOn
(
AndroidSchedulers
.
from
(
Looper
.
myLooper
()
!!
))
.
filter
{
realmSpotlightResults
->
realmSpotlightResults
.
isLoaded
&&
realmSpotlightResults
.
isValid
}
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/repositories/RealmSpotlightRoomRepository.java
View file @
5bbd3f7f
...
...
@@ -2,20 +2,20 @@ package chat.rocket.persistence.realm.repositories;
import
android.os.Looper
;
import
android.support.v4.util.Pair
;
import
io.reactivex.Flowable
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.realm.Case
;
import
io.realm.Sort
;
import
java.util.ArrayList
;
import
java.util.List
;
import
chat.rocket.core.SortDirection
;
import
chat.rocket.core.models.SpotlightRoom
;
import
chat.rocket.core.repositories.SpotlightRoomRepository
;
import
chat.rocket.persistence.realm.RealmStore
;
import
chat.rocket.persistence.realm.models.ddp.RealmRoom
;
import
chat.rocket.persistence.realm.models.ddp.RealmSpotlightRoom
;
import
hu.akarnokd.rxjava.interop.RxJavaInterop
;
import
io.reactivex.Flowable
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.realm.Case
;
import
io.realm.Sort
;
public
class
RealmSpotlightRoomRepository
extends
RealmRepository
implements
SpotlightRoomRepository
{
...
...
@@ -34,8 +34,7 @@ public class RealmSpotlightRoomRepository extends RealmRepository implements Spo
return
Flowable
.
empty
();
}
return
RxJavaInterop
.
toV2Flowable
(
pair
.
first
.
where
(
RealmSpotlightRoom
.
class
)
return
pair
.
first
.
where
(
RealmSpotlightRoom
.
class
)
.
like
(
RealmSpotlightRoom
.
Columns
.
NAME
,
"*"
+
name
+
"*"
,
Case
.
INSENSITIVE
)
.
beginGroup
()
.
equalTo
(
RealmSpotlightRoom
.
Columns
.
TYPE
,
RealmRoom
.
TYPE_CHANNEL
)
...
...
@@ -43,7 +42,7 @@ public class RealmSpotlightRoomRepository extends RealmRepository implements Spo
.
equalTo
(
RealmSpotlightRoom
.
Columns
.
TYPE
,
RealmRoom
.
TYPE_PRIVATE
)
.
endGroup
()
.
findAllSorted
(
RealmSpotlightRoom
.
Columns
.
NAME
,
direction
.
equals
(
SortDirection
.
ASC
)
?
Sort
.
ASCENDING
:
Sort
.
DESCENDING
)
.
as
Observable
()
);
.
as
Flowable
(
);
},
pair
->
close
(
pair
.
first
,
pair
.
second
)
)
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/repositories/RealmSpotlightUserRepository.java
View file @
5bbd3f7f
...
...
@@ -2,19 +2,19 @@ package chat.rocket.persistence.realm.repositories;
import
android.os.Looper
;
import
android.support.v4.util.Pair
;
import
io.reactivex.Flowable
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.realm.Case
;
import
io.realm.Sort
;
import
java.util.ArrayList
;
import
java.util.List
;
import
chat.rocket.core.SortDirection
;
import
chat.rocket.core.models.SpotlightUser
;
import
chat.rocket.core.repositories.SpotlightUserRepository
;
import
chat.rocket.persistence.realm.RealmStore
;
import
chat.rocket.persistence.realm.models.ddp.RealmSpotlightUser
;
import
hu.akarnokd.rxjava.interop.RxJavaInterop
;
import
io.reactivex.Flowable
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.realm.Case
;
import
io.realm.Sort
;
public
class
RealmSpotlightUserRepository
extends
RealmRepository
implements
SpotlightUserRepository
{
...
...
@@ -33,8 +33,7 @@ public class RealmSpotlightUserRepository extends RealmRepository implements Spo
return
Flowable
.
empty
();
}
return
RxJavaInterop
.
toV2Flowable
(
pair
.
first
.
where
(
RealmSpotlightUser
.
class
)
return
pair
.
first
.
where
(
RealmSpotlightUser
.
class
)
.
beginGroup
()
.
like
(
RealmSpotlightUser
.
Columns
.
USERNAME
,
"*"
+
name
+
"*"
,
Case
.
INSENSITIVE
)
.
isNull
(
RealmSpotlightUser
.
Columns
.
NAME
)
...
...
@@ -46,7 +45,7 @@ public class RealmSpotlightUserRepository extends RealmRepository implements Spo
.
endGroup
()
.
findAllSorted
(
RealmSpotlightUser
.
Columns
.
USERNAME
,
direction
.
equals
(
SortDirection
.
ASC
)
?
Sort
.
ASCENDING
:
Sort
.
DESCENDING
)
.
as
Observable
()
);
.
as
Flowable
(
);
},
pair
->
close
(
pair
.
first
,
pair
.
second
)
)
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/repositories/RealmUserRepository.java
View file @
5bbd3f7f
...
...
@@ -12,7 +12,6 @@ import chat.rocket.core.models.User;
import
chat.rocket.core.repositories.UserRepository
;
import
chat.rocket.persistence.realm.RealmStore
;
import
chat.rocket.persistence.realm.models.ddp.RealmUser
;
import
hu.akarnokd.rxjava.interop.RxJavaInterop
;
import
io.reactivex.Flowable
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.realm.Case
;
...
...
@@ -36,10 +35,9 @@ public class RealmUserRepository extends RealmRepository implements UserReposito
return
Flowable
.
empty
();
}
return
RxJavaInterop
.
toV2Flowable
(
pair
.
first
.
where
(
RealmUser
.
class
)
return
pair
.
first
.
where
(
RealmUser
.
class
)
.
findAll
()
.
as
Observable
()
);
.
as
Flowable
(
);
},
pair
->
close
(
pair
.
first
,
pair
.
second
))
.
unsubscribeOn
(
AndroidSchedulers
.
from
(
Looper
.
myLooper
()))
...
...
@@ -71,11 +69,10 @@ public class RealmUserRepository extends RealmRepository implements UserReposito
return
Flowable
.
empty
();
}
return
RxJavaInterop
.
toV2Flowable
(
pair
.
first
.
where
(
RealmUser
.
class
)
return
pair
.
first
.
where
(
RealmUser
.
class
)
.
isNotEmpty
(
RealmUser
.
EMAILS
)
.
findAll
()
.<
RealmResults
<
RealmUser
>>
as
Observable
()
);
.<
RealmResults
<
RealmUser
>>
as
Flowable
(
);
},
pair
->
close
(
pair
.
first
,
pair
.
second
));
}
...
...
@@ -114,11 +111,9 @@ public class RealmUserRepository extends RealmRepository implements UserReposito
return
Flowable
.
just
(
Optional
.
absent
());
}
return
RxJavaInterop
.
toV2Flowable
(
realmUser
.<
RealmUser
>
asObservable
()
return
realmUser
.<
RealmUser
>
asFlowable
()
.
filter
(
user
->
user
.
isLoaded
()
&&
user
.
isValid
())
.
map
(
Optional:
:
of
)
)
;
.
map
(
Optional:
:
of
);
}
@Override
...
...
@@ -139,11 +134,10 @@ public class RealmUserRepository extends RealmRepository implements UserReposito
return
Flowable
.
empty
();
}
return
RxJavaInterop
.
toV2Flowable
(
pair
.
first
.
where
(
RealmUser
.
class
)
return
pair
.
first
.
where
(
RealmUser
.
class
)
.
like
(
RealmUser
.
USERNAME
,
"*"
+
name
+
"*"
,
Case
.
INSENSITIVE
)
.
findAllSorted
(
RealmUser
.
USERNAME
,
Sort
.
DESCENDING
)
.
as
Observable
()
);
.
as
Flowable
(
);
},
pair
->
close
(
pair
.
first
,
pair
.
second
));
}
...
...
rocket-chat-android-widgets/build.gradle
View file @
5bbd3f7f
...
...
@@ -2,16 +2,6 @@ apply plugin: 'com.android.library'
apply
plugin:
'kotlin-android'
apply
plugin:
'kotlin-android-extensions'
buildscript
{
repositories
{
jcenter
()
mavenCentral
()
}
dependencies
{
classpath
'com.android.tools.build:gradle:2.3.3'
classpath
"org.jetbrains.kotlin:kotlin-gradle-plugin:$rootProject.ext.kotlinVersion"
}
}
android
{
compileSdkVersion
rootProject
.
ext
.
compileSdkVersion
buildToolsVersion
rootProject
.
ext
.
buildToolsVersion
...
...
@@ -21,7 +11,6 @@ android {
targetSdkVersion
rootProject
.
ext
.
targetSdkVersion
versionCode
1
versionName
"1"
vectorDrawables
.
useSupportLibrary
=
true
}
...
...
@@ -40,7 +29,6 @@ android {
ext
{
frescoVersion
=
'1.4.0'
rxbindingVersion
=
'2.0.0'
}
dependencies
{
compile
project
(
':rocket-chat-core'
)
...
...
@@ -49,18 +37,18 @@ dependencies {
compile
supportDependencies
.
annotation
compile
supportDependencies
.
cardView
compile
supportDependencies
.
designSupportLibrary
compile
supportDependencies
.
constrainLayout
compile
supportDependencies
.
kotlin
compile
supportDependencies
.
constrain
t
Layout
compile
supportDependencies
.
supportV13
compile
rxbindingDependencies
.
rxBinding
compile
rxbindingDependencies
.
rxBindingSupport
compile
"com.android.support:support-v13:$rootProject.ext.supportLibraryVersion"
testCompile
"org.jetbrains.kotlin:kotlin-test:$rootProject.ext.kotlinVersion"
testCompile
"org.jetbrains.kotlin:kotlin-test-junit:$rootProject.ext.kotlinVersion"
compile
"org.jetbrains.kotlin:kotlin-stdlib-jre7:$rootProject.ext.kotlinVersion"
compile
'org.nibor.autolink:autolink:0.6.0'
compile
'com.github.yusukeiwaki.android-widget:widget-fontawesome:0.0.1'
compile
"com.facebook.fresco:fresco:$frescoVersion"
compile
"com.facebook.fresco:imagepipeline-okhttp3:$frescoVersion"
compile
'com.caverock:androidsvg:1.2.1'
testCompile
"org.jetbrains.kotlin:kotlin-test-junit:$rootProject.ext.kotlinVersion"
testCompile
"org.jetbrains.kotlin:kotlin-test:$rootProject.ext.kotlinVersion"
testCompile
'junit:junit:4.12'
testCompile
"org.mockito:mockito-core:2.7.19"
}
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/RocketChatAvatar.java
View file @
5bbd3f7f
...
...
@@ -7,9 +7,11 @@ import android.os.Build;
import
android.util.AttributeSet
;
import
android.view.LayoutInflater
;
import
android.widget.FrameLayout
;
import
chat.rocket.android.widget.helper.FrescoHelper
;
import
com.facebook.drawee.view.SimpleDraweeView
;
import
chat.rocket.android.widget.helper.FrescoHelper
;
public
class
RocketChatAvatar
extends
FrameLayout
{
private
SimpleDraweeView
simpleDraweeViewAvatar
;
...
...
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/helper/IconProvider.java
View file @
5bbd3f7f
...
...
@@ -3,6 +3,7 @@ package chat.rocket.android.widget.helper;
import
android.support.annotation.StringRes
;
import
java.util.HashMap
;
import
chat.rocket.android.widget.R
;
public
class
IconProvider
{
...
...
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/helper/InlineHightlighter.java
View file @
5bbd3f7f
...
...
@@ -15,6 +15,7 @@ import android.widget.TextView;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
import
chat.rocket.android.widget.R
;
public
class
InlineHightlighter
{
...
...
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/helper/LinkMovementMethodCompat.java
View file @
5bbd3f7f
...
...
@@ -5,7 +5,6 @@ import android.text.Selection;
import
android.text.Spannable
;
import
android.text.method.LinkMovementMethod
;
import
android.text.method.MovementMethod
;
import
android.text.method.Touch
;
import
android.text.style.ClickableSpan
;
import
android.view.MotionEvent
;
import
android.widget.TextView
;
...
...
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/helper/Linkify.java
View file @
5bbd3f7f
...
...
@@ -3,6 +3,7 @@ package chat.rocket.android.widget.helper;
import
android.text.SpannableString
;
import
android.text.Spanned
;
import
android.widget.TextView
;
import
org.nibor.autolink.LinkExtractor
;
import
org.nibor.autolink.LinkSpan
;
import
org.nibor.autolink.LinkType
;
...
...
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/internal/ExtraActionPickerDialogFragment.java
View file @
5bbd3f7f
...
...
@@ -6,6 +6,7 @@ import android.support.v4.app.Fragment;
import
android.support.v7.widget.RecyclerView
;
import
java.util.List
;
import
chat.rocket.android.widget.R
;
import
chat.rocket.android.widget.layouthelper.MessageExtraActionListAdapter
;
import
chat.rocket.android.widget.message.MessageExtraActionItemPresenter
;
...
...
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/layouthelper/MessageExtraActionListAdapter.java
View file @
5bbd3f7f
...
...
@@ -6,6 +6,7 @@ import android.view.View;
import
android.view.ViewGroup
;
import
java.util.List
;
import
chat.rocket.android.widget.R
;
import
chat.rocket.android.widget.message.MessageExtraActionItemPresenter
;
...
...
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/RocketChatMessageAttachmentsLayout.java
View file @
5bbd3f7f
...
...
@@ -16,6 +16,12 @@ import android.view.View;
import
android.view.ViewGroup
;
import
android.widget.LinearLayout
;
import
android.widget.TextView
;
import
com.facebook.drawee.generic.GenericDraweeHierarchyBuilder
;
import
com.facebook.drawee.view.SimpleDraweeView
;
import
java.util.List
;
import
chat.rocket.android.widget.AbsoluteUrl
;
import
chat.rocket.android.widget.R
;
import
chat.rocket.android.widget.helper.FrescoHelper
;
...
...
@@ -24,10 +30,6 @@ import chat.rocket.core.models.AttachmentAuthor;
import
chat.rocket.core.models.AttachmentField
;
import
chat.rocket.core.models.AttachmentTitle
;
import
com.facebook.drawee.generic.GenericDraweeHierarchyBuilder
;
import
com.facebook.drawee.view.SimpleDraweeView
;
import
java.util.List
;
/**
*/
public
class
RocketChatMessageAttachmentsLayout
extends
LinearLayout
{
...
...
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/RocketChatMessageLayout.java
View file @
5bbd3f7f
...
...
@@ -8,6 +8,7 @@ import android.util.AttributeSet;
import
android.view.LayoutInflater
;
import
android.widget.LinearLayout
;
import
android.widget.TextView
;
import
com.emojione.Emojione
;
import
chat.rocket.android.widget.R
;
...
...
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/RocketChatMessageUrlsLayout.java
View file @
5bbd3f7f
...
...
@@ -11,12 +11,14 @@ import android.view.LayoutInflater;
import
android.view.View
;
import
android.widget.LinearLayout
;
import
android.widget.TextView
;
import
chat.rocket.android.widget.helper.FrescoHelper
;
import
com.facebook.drawee.view.SimpleDraweeView
;
import
java.util.List
;
import
java.util.Map
;
import
chat.rocket.android.widget.R
;
import
chat.rocket.android.widget.helper.FrescoHelper
;
import
chat.rocket.android.widget.helper.ImageFormat
;
import
chat.rocket.core.models.WebContent
;
import
chat.rocket.core.models.WebContentHeaders
;
...
...
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/autocomplete/AutocompleteManager.java
View file @
5bbd3f7f
...
...
@@ -12,6 +12,12 @@ import android.widget.RelativeLayout;
import
com.jakewharton.rxbinding2.widget.RxTextView
;
import
com.jakewharton.rxbinding2.widget.TextViewAfterTextChangeEvent
;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.concurrent.TimeUnit
;
import
chat.rocket.android.widget.R
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.reactivex.annotations.NonNull
;
import
io.reactivex.disposables.CompositeDisposable
;
...
...
@@ -20,11 +26,6 @@ import io.reactivex.functions.Consumer;
import
io.reactivex.functions.Function
;
import
io.reactivex.internal.util.AppendOnlyLinkedArrayList
;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.concurrent.TimeUnit
;
import
chat.rocket.android.widget.R
;
public
class
AutocompleteManager
{
private
final
Map
<
String
,
AutocompleteSource
>
autocompleteSourceMap
=
new
HashMap
<>();
...
...
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/autocomplete/AutocompleteSource.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
widget
.
message
.
autocomplete
;
import
android.support.annotation.NonNull
;
import
io.reactivex.disposables.Disposable
;
public
abstract
class
AutocompleteSource
<
A
extends
AutocompleteAdapter
,
I
extends
AutocompleteItem
>
{
...
...
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/autocomplete/channel/ChannelSource.java
View file @
5bbd3f7f
...
...
@@ -2,19 +2,19 @@ package chat.rocket.android.widget.message.autocomplete.channel;
import
android.support.annotation.NonNull
;
import
io.reactivex.Flowable
;
import
io.reactivex.Scheduler
;
import
io.reactivex.disposables.Disposable
;
import
io.reactivex.functions.Consumer
;
import
io.reactivex.functions.Function
;
import
org.reactivestreams.Publisher
;
import
java.util.ArrayList
;
import
java.util.List
;
import
chat.rocket.android.widget.message.autocomplete.AutocompleteSource
;
import
chat.rocket.core.interactors.AutocompleteChannelInteractor
;
import
chat.rocket.core.models.SpotlightRoom
;
import
io.reactivex.Flowable
;
import
io.reactivex.Scheduler
;
import
io.reactivex.disposables.Disposable
;
import
io.reactivex.functions.Consumer
;
import
io.reactivex.functions.Function
;
public
class
ChannelSource
extends
AutocompleteSource
<
ChannelAdapter
,
ChannelItem
>
{
...
...
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/autocomplete/user/UserSource.java
View file @
5bbd3f7f
package
chat
.
rocket
.
android
.
widget
.
message
.
autocomplete
.
user
;
import
android.support.annotation.NonNull
;
import
io.reactivex.Flowable
;
import
io.reactivex.Scheduler
;
import
io.reactivex.disposables.Disposable
;
import
io.reactivex.functions.Consumer
;
import
io.reactivex.functions.Function
;
import
org.reactivestreams.Publisher
;
import
java.util.ArrayList
;
import
java.util.List
;
import
chat.rocket.android.widget.AbsoluteUrl
;
import
chat.rocket.android.widget.helper.UserStatusProvider
;
import
chat.rocket.android.widget.message.autocomplete.AutocompleteSource
;
import
chat.rocket.core.interactors.AutocompleteUserInteractor
;
import
chat.rocket.core.models.SpotlightUser
;
import
io.reactivex.Flowable
;
import
io.reactivex.Scheduler
;
import
io.reactivex.disposables.Disposable
;
import
io.reactivex.functions.Consumer
;
import
io.reactivex.functions.Function
;
public
class
UserSource
extends
AutocompleteSource
<
UserAdapter
,
UserItem
>
{
...
...
rocket-chat-android-widgets/src/main/res/layout/message_composer.xml
View file @
5bbd3f7f
...
...
@@ -32,11 +32,11 @@
android:id=
"@+id/reply_icon"
android:layout_width=
"24dp"
android:layout_height=
"24dp"
android:layout_marginRight=
"8dp"
android:layout_marginEnd=
"8dp"
android:layout_centerVertical=
"true"
android:layout_alignParentStart=
"true"
android:layout_alignParentLeft=
"true"
android:layout_alignParentStart=
"true"
android:layout_centerVertical=
"true"
android:layout_marginEnd=
"8dp"
android:layout_marginRight=
"8dp"
android:adjustViewBounds=
"true"
app:srcCompat=
"@drawable/ic_reply"
app:tint=
"@color/color_accent"
/>
...
...
@@ -45,11 +45,11 @@
android:id=
"@+id/reply_cancel"
android:layout_width=
"24dp"
android:layout_height=
"24dp"
android:layout_marginLeft=
"8dp"
android:layout_marginStart=
"8dp"
android:layout_centerVertical=
"true"
android:layout_alignParentEnd=
"true"
android:layout_alignParentRight=
"true"
android:layout_centerVertical=
"true"
android:layout_marginLeft=
"8dp"
android:layout_marginStart=
"8dp"
android:adjustViewBounds=
"true"
app:srcCompat=
"@drawable/ic_close"
app:tint=
"@color/color_icon_composer"
/>
...
...
@@ -59,10 +59,10 @@
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_alignBaseline=
"@id/reply_username"
android:layout_toEndOf=
"@+id/reply_thumb"
android:layout_toLeftOf=
"@+id/reply_cancel"
android:layout_toStartOf=
"@id/reply_cancel"
android:layout_toRightOf=
"@+id/reply_thumb"
android:layout_to
EndOf=
"@+id/reply_thumb
"
android:layout_to
StartOf=
"@id/reply_cancel
"
android:ellipsize=
"end"
android:maxLines=
"1"
android:textColor=
"@color/color_accent"
...
...
@@ -73,13 +73,13 @@
android:id=
"@+id/reply_thumb"
android:layout_width=
"32dp"
android:layout_height=
"wrap_content"
android:layout_marginRight=
"4dp"
android:layout_marginEnd=
"4dp"
android:layout_toRightOf=
"@+id/reply_icon"
android:layout_toEndOf=
"@+id/reply_icon"
android:layout_alignBottom=
"@+id/reply_message"
android:layout_alignTop=
"@+id/reply_username"
android:layout_centerVertical=
"true"
android:layout_marginEnd=
"4dp"
android:layout_marginRight=
"4dp"
android:layout_toEndOf=
"@+id/reply_icon"
android:layout_toRightOf=
"@+id/reply_icon"
android:visibility=
"gone"
fresco:actualImageScaleType=
"fitCenter"
/>
...
...
@@ -88,10 +88,10 @@
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_below=
"@id/reply_username"
android:layout_toEndOf=
"@+id/reply_thumb"
android:layout_toLeftOf=
"@+id/reply_cancel"
android:layout_toStartOf=
"@id/reply_cancel"
android:layout_toRightOf=
"@+id/reply_thumb"
android:layout_to
EndOf=
"@+id/reply_thumb
"
android:layout_to
StartOf=
"@id/reply_cancel
"
android:ellipsize=
"end"
android:maxLines=
"1"
tools:text=
"Message"
/>
...
...
@@ -128,29 +128,34 @@
<FrameLayout
android:id=
"@+id/container"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginEnd=
"16dp"
android:layout_marginLeft=
"16dp"
android:layout_marginRight=
"16dp"
android:layout_marginStart=
"16dp"
app:layout_constraintBottom_toBottomOf=
"@+id/editor"
android:layout_height=
"0dp"
app:layout_constraintBottom_toBottomOf=
"parent"
app:layout_constraintLeft_toRightOf=
"@+id/editor"
app:layout_constraintRight_toRightOf=
"parent"
app:layout_constraintTop_toTopOf=
"
@+id/editor
"
>
app:layout_constraintTop_toTopOf=
"
parent
"
>
<ImageButton
android:id=
"@+id/button_attach"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:layout_gravity=
"center_vertical"
android:background=
"?attr/selectableItemBackgroundBorderless"
android:paddingEnd=
"16dp"
android:paddingLeft=
"16dp"
android:paddingRight=
"16dp"
android:paddingStart=
"16dp"
android:tint=
"@color/color_icon_composer"
app:srcCompat=
"@drawable/ic_attach_file_black_24dp"
/>
<ImageButton
android:id=
"@+id/button_send"
android:layout_width=
"
wrap_cont
ent"
android:layout_height=
"
wrap_cont
ent"
android:layout_width=
"
match_par
ent"
android:layout_height=
"
match_par
ent"
android:background=
"?attr/selectableItemBackgroundBorderless"
android:paddingEnd=
"16dp"
android:paddingLeft=
"16dp"
android:paddingRight=
"16dp"
android:paddingStart=
"16dp"
android:tint=
"@color/color_accent"
app:srcCompat=
"@drawable/ic_send_black_24dp"
/>
</FrameLayout>
...
...
rocket-chat-android-widgets/src/main/res/layout/server_row.xml
View file @
5bbd3f7f
...
...
@@ -53,7 +53,7 @@
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintStart_toEndOf=
"@+id/drawee_server_button"
app:layout_constraintTop_toBottomOf=
"@+id/text_view_site_name_label"
tools:text=
"
demo
.rocket.chat"
/>
tools:text=
"
open
.rocket.chat"
/>
<ImageView
android:id=
"@+id/selected_server_dot"
...
...
rocket-chat-core/build.gradle
View file @
5bbd3f7f
plugins
{
id
"org.jetbrains.kotlin.jvm"
version
"1.1.4-2"
}
apply
plugin:
'org.jetbrains.kotlin.jvm'
apply
plugin:
'idea'
apply
plugin:
'java'
dependencies
{
compile
fileTree
(
dir:
'libs'
,
include:
[
'*.jar'
])
compile
extraDependencies
.
rxJava
compile
extraDependencies
.
optional
compile
"org.jetbrains.kotlin:kotlin-stdlib-jre7:$rootProject.ext.kotlinVersion"
compile
'com.google.code.findbugs:jsr305:3.0.1'
compile
'com.hadisatrio:Optional:v1.0.1'
compile
'com.google.code.findbugs:jsr305:3.0.2'
compileOnly
'com.google.auto.value:auto-value:1.3'
kapt
'com.google.auto.value:auto-value:1.3'
kapt
'com.gabrielittner.auto.value:auto-value-with:1.0.0'
testCompile
'junit:junit:4.12'
testCompile
"org.mockito:mockito-inline:2.8.9"
}
...
...
rocket-chat-core/src/main/java/chat/rocket/core/SyncState.java
View file @
5bbd3f7f
...
...
@@ -8,4 +8,7 @@ public interface SyncState {
int
SYNCING
=
1
;
int
SYNCED
=
2
;
int
FAILED
=
3
;
int
DELETE_NOT_SYNCED
=
4
;
int
DELETING
=
5
;
int
DELETE_FAILED
=
6
;
}
rocket-chat-core/src/main/java/chat/rocket/core/interactors/AutocompleteChannelInteractor.kt
View file @
5bbd3f7f
package
chat.rocket.core.interactors
import
io.reactivex.Flowable
import
java.util.ArrayList
import
chat.rocket.core.SortDirection
import
chat.rocket.core.models.Room
import
chat.rocket.core.models.SpotlightRoom
...
...
@@ -11,8 +8,10 @@ import chat.rocket.core.repositories.SpotlightRoomRepository
import
chat.rocket.core.temp.TempSpotlightRoomCaller
import
chat.rocket.core.utils.Pair
import
chat.rocket.core.utils.Triple
import
io.reactivex.Flowable
import
io.reactivex.functions.BiFunction
import
io.reactivex.functions.Function3
import
java.util.*
class
AutocompleteChannelInteractor
(
private
val
roomRepository
:
RoomRepository
,
private
val
spotlightRoomRepository
:
SpotlightRoomRepository
,
...
...
rocket-chat-core/src/main/java/chat/rocket/core/interactors/AutocompleteUserInteractor.kt
View file @
5bbd3f7f
...
...
@@ -12,7 +12,7 @@ import chat.rocket.core.temp.TempSpotlightUserCaller
import
chat.rocket.core.utils.Triple
import
io.reactivex.Flowable
import
io.reactivex.functions.Function3
import
java.util.
ArrayList
import
java.util.
*
class
AutocompleteUserInteractor
(
private
val
room
:
Room
,
private
val
userRepository
:
UserRepository
,
...
...
rocket-chat-core/src/main/java/chat/rocket/core/interactors/CanCreateRoomInteractor.kt
View file @
5bbd3f7f
...
...
@@ -2,11 +2,10 @@ package chat.rocket.core.interactors
import
chat.rocket.core.models.Session
import
chat.rocket.core.models.User
import
io.reactivex.Flowable
import
io.reactivex.Single
import
chat.rocket.core.repositories.UserRepository
import
com.hadisatrio.optional.Optional
import
io.reactivex.Flowable
import
io.reactivex.Single
import
io.reactivex.functions.Function3
class
CanCreateRoomInteractor
(
private
val
userRepository
:
UserRepository
,
...
...
rocket-chat-core/src/main/java/chat/rocket/core/interactors/EditMessageInteractor.kt
View file @
5bbd3f7f
...
...
@@ -2,8 +2,14 @@ package chat.rocket.core.interactors
import
chat.rocket.core.PermissionsConstants
import
chat.rocket.core.PublicSettingsConstants
import
chat.rocket.core.models.*
import
chat.rocket.core.repositories.*
import
chat.rocket.core.models.Message
import
chat.rocket.core.models.PublicSetting
import
chat.rocket.core.models.Room
import
chat.rocket.core.models.User
import
chat.rocket.core.repositories.MessageRepository
import
chat.rocket.core.repositories.PublicSettingRepository
import
chat.rocket.core.repositories.RoomRepository
import
chat.rocket.core.repositories.UserRepository
import
chat.rocket.core.utils.Pair
import
com.hadisatrio.optional.Optional
import
io.reactivex.Single
...
...
rocket-chat-core/src/main/java/chat/rocket/core/interactors/MessageInteractor.kt
View file @
5bbd3f7f
package
chat.rocket.core.interactors
import
com.hadisatrio.optional.Optional
import
io.reactivex.Flowable
import
io.reactivex.Single
import
java.util.UUID
import
chat.rocket.core.SyncState
import
chat.rocket.core.models.Message
import
chat.rocket.core.models.Room
...
...
@@ -11,6 +7,10 @@ import chat.rocket.core.models.RoomHistoryState
import
chat.rocket.core.models.User
import
chat.rocket.core.repositories.MessageRepository
import
chat.rocket.core.repositories.RoomRepository
import
com.hadisatrio.optional.Optional
import
io.reactivex.Flowable
import
io.reactivex.Single
import
java.util.*
class
MessageInteractor
(
private
val
messageRepository
:
MessageRepository
,
private
val
roomRepository
:
RoomRepository
)
{
...
...
@@ -76,7 +76,14 @@ class MessageInteractor(private val messageRepository: MessageRepository,
}
fun
delete
(
message
:
Message
):
Single
<
Boolean
>
{
return
messageRepository
.
delete
(
message
)
return
messageRepository
.
save
(
message
.
withSyncState
(
SyncState
.
DELETE_NOT_SYNCED
))
}
/**
* Resets the message syncstate to SYNCED after a user has accepted a failed delete
*/
fun
acceptDeleteFailure
(
message
:
Message
):
Single
<
Boolean
>
{
return
messageRepository
.
save
(
message
.
withSyncState
(
SyncState
.
SYNCED
))
}
fun
unreadCountFor
(
room
:
Room
,
user
:
User
):
Single
<
Int
>
{
...
...
rocket-chat-core/src/main/java/chat/rocket/core/interactors/PermissionInteractor.kt
View file @
5bbd3f7f
...
...
@@ -3,7 +3,9 @@ package chat.rocket.core.interactors
import
chat.rocket.core.models.Permission
import
chat.rocket.core.models.Room
import
chat.rocket.core.models.RoomRole
import
chat.rocket.core.repositories.*
import
chat.rocket.core.repositories.PermissionRepository
import
chat.rocket.core.repositories.RoomRoleRepository
import
chat.rocket.core.repositories.UserRepository
import
chat.rocket.core.utils.Pair
import
com.hadisatrio.optional.Optional
import
io.reactivex.Single
...
...
rocket-chat-core/src/main/java/chat/rocket/core/interactors/RoomInteractor.kt
View file @
5bbd3f7f
package
chat.rocket.core.interactors
import
io.reactivex.Flowable
import
chat.rocket.core.SortDirection
import
chat.rocket.core.models.Room
import
chat.rocket.core.repositories.RoomRepository
import
io.reactivex.Flowable
class
RoomInteractor
(
private
val
roomRepository
:
RoomRepository
)
{
...
...
rocket-chat-core/src/main/java/chat/rocket/core/interactors/SessionInteractor.kt
View file @
5bbd3f7f
package
chat.rocket.core.interactors
import
chat.rocket.core.models.Session
import
chat.rocket.core.repositories.SessionRepository
import
com.hadisatrio.optional.Optional
import
io.reactivex.Flowable
import
io.reactivex.Single
import
chat.rocket.core.models.Session
import
chat.rocket.core.repositories.SessionRepository
class
SessionInteractor
(
private
val
sessionRepository
:
SessionRepository
)
{
companion
object
{
...
...
rocket-chat-core/src/main/java/chat/rocket/core/interactors/UserInteractor.java
View file @
5bbd3f7f
package
chat
.
rocket
.
core
.
interactors
;
import
io.reactivex.Flowable
;
import
java.util.List
;
import
chat.rocket.core.models.User
;
import
chat.rocket.core.repositories.UserRepository
;
import
io.reactivex.Flowable
;
public
class
UserInteractor
{
...
...
rocket-chat-core/src/main/java/chat/rocket/core/models/Attachment.java
View file @
5bbd3f7f
...
...
@@ -3,6 +3,7 @@ package chat.rocket.core.models;
import
com.google.auto.value.AutoValue
;
import
java.util.List
;
import
javax.annotation.Nullable
;
@AutoValue
...
...
rocket-chat-core/src/main/java/chat/rocket/core/models/Message.java
View file @
5bbd3f7f
...
...
@@ -3,6 +3,7 @@ package chat.rocket.core.models;
import
com.google.auto.value.AutoValue
;
import
java.util.List
;
import
javax.annotation.Nullable
;
@AutoValue
...
...
rocket-chat-core/src/main/java/chat/rocket/core/models/User.java
View file @
5bbd3f7f
...
...
@@ -3,6 +3,7 @@ package chat.rocket.core.models;
import
com.google.auto.value.AutoValue
;
import
java.util.List
;
import
javax.annotation.Nullable
;
@AutoValue
...
...
rocket-chat-core/src/main/java/chat/rocket/core/models/WebContent.java
View file @
5bbd3f7f
...
...
@@ -3,6 +3,7 @@ package chat.rocket.core.models;
import
com.google.auto.value.AutoValue
;
import
java.util.Map
;
import
javax.annotation.Nullable
;
@AutoValue
...
...
rocket-chat-core/src/main/java/chat/rocket/core/repositories/LoginServiceConfigurationRepository.java
View file @
5bbd3f7f
package
chat
.
rocket
.
core
.
repositories
;
import
com.hadisatrio.optional.Optional
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
import
java.util.List
;
import
chat.rocket.core.models.LoginServiceConfiguration
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
public
interface
LoginServiceConfigurationRepository
{
...
...
rocket-chat-core/src/main/java/chat/rocket/core/repositories/MessageRepository.java
View file @
5bbd3f7f
package
chat
.
rocket
.
core
.
repositories
;
import
com.hadisatrio.optional.Optional
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
import
java.util.List
;
import
chat.rocket.core.models.Message
;
import
chat.rocket.core.models.Room
;
import
chat.rocket.core.models.User
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
public
interface
MessageRepository
{
...
...
rocket-chat-core/src/main/java/chat/rocket/core/repositories/PermissionRepository.java
View file @
5bbd3f7f
package
chat
.
rocket
.
core
.
repositories
;
import
com.hadisatrio.optional.Optional
;
import
io.reactivex.Single
;
import
chat.rocket.core.models.Permission
;
import
io.reactivex.Single
;
public
interface
PermissionRepository
{
...
...
rocket-chat-core/src/main/java/chat/rocket/core/repositories/PublicSettingRepository.java
View file @
5bbd3f7f
package
chat
.
rocket
.
core
.
repositories
;
import
com.hadisatrio.optional.Optional
;
import
io.reactivex.Single
;
import
chat.rocket.core.models.PublicSetting
;
import
io.reactivex.Single
;
public
interface
PublicSettingRepository
{
...
...
rocket-chat-core/src/main/java/chat/rocket/core/repositories/RoomRepository.java
View file @
5bbd3f7f
package
chat
.
rocket
.
core
.
repositories
;
import
com.hadisatrio.optional.Optional
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
import
java.util.List
;
import
chat.rocket.core.SortDirection
;
import
chat.rocket.core.models.Room
;
import
chat.rocket.core.models.RoomHistoryState
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
public
interface
RoomRepository
{
...
...
rocket-chat-core/src/main/java/chat/rocket/core/repositories/RoomRoleRepository.java
View file @
5bbd3f7f
package
chat
.
rocket
.
core
.
repositories
;
import
com.hadisatrio.optional.Optional
;
import
io.reactivex.Single
;
import
chat.rocket.core.models.Room
;
import
chat.rocket.core.models.RoomRole
;
import
chat.rocket.core.models.User
;
import
io.reactivex.Single
;
public
interface
RoomRoleRepository
{
...
...
rocket-chat-core/src/main/java/chat/rocket/core/repositories/ServerInfoRepository.java
View file @
5bbd3f7f
...
...
@@ -2,9 +2,8 @@ package chat.rocket.core.repositories;
import
com.hadisatrio.optional.Optional
;
import
io.reactivex.Flowable
;
import
chat.rocket.core.models.ServerInfo
;
import
io.reactivex.Flowable
;
public
interface
ServerInfoRepository
{
...
...
rocket-chat-core/src/main/java/chat/rocket/core/repositories/SessionRepository.java
View file @
5bbd3f7f
package
chat
.
rocket
.
core
.
repositories
;
import
com.hadisatrio.optional.Optional
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
import
chat.rocket.core.models.Session
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
public
interface
SessionRepository
{
...
...
rocket-chat-core/src/main/java/chat/rocket/core/repositories/SpotlightRoomRepository.java
View file @
5bbd3f7f
package
chat
.
rocket
.
core
.
repositories
;
import
io.reactivex.Flowable
;
import
java.util.List
;
import
chat.rocket.core.SortDirection
;
import
chat.rocket.core.models.SpotlightRoom
;
import
io.reactivex.Flowable
;
public
interface
SpotlightRoomRepository
{
...
...
rocket-chat-core/src/main/java/chat/rocket/core/repositories/SpotlightUserRepository.java
View file @
5bbd3f7f
package
chat
.
rocket
.
core
.
repositories
;
import
io.reactivex.Flowable
;
import
java.util.List
;
import
chat.rocket.core.SortDirection
;
import
chat.rocket.core.models.SpotlightUser
;
import
io.reactivex.Flowable
;
public
interface
SpotlightUserRepository
{
...
...
rocket-chat-core/src/main/java/chat/rocket/core/repositories/UserRepository.kt
View file @
5bbd3f7f
package
chat.rocket.core.repositories
import
chat.rocket.core.models.User
import
com.hadisatrio.optional.Optional
import
io.reactivex.Flowable
import
chat.rocket.core.models.User
interface
UserRepository
{
...
...
rocket-chat-core/src/test/java/chat/rocket/core/interactors/AutocompleteChannelInteractorTest.java
View file @
5bbd3f7f
package
chat
.
rocket
.
core
.
interactors
;
import
static
org
.
mockito
.
Mockito
.*;
import
io.reactivex.Flowable
;
import
io.reactivex.subscribers.TestSubscriber
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
...
...
@@ -12,12 +8,23 @@ import org.mockito.junit.MockitoJUnitRunner;
import
java.util.ArrayList
;
import
java.util.List
;
import
chat.rocket.core.SortDirection
;
import
chat.rocket.core.models.Room
;
import
chat.rocket.core.models.SpotlightRoom
;
import
chat.rocket.core.repositories.RoomRepository
;
import
chat.rocket.core.repositories.SpotlightRoomRepository
;
import
chat.rocket.core.temp.TempSpotlightRoomCaller
;
import
io.reactivex.Flowable
;
import
io.reactivex.subscribers.TestSubscriber
;
import
static
org
.
mockito
.
Mockito
.
any
;
import
static
org
.
mockito
.
Mockito
.
anyInt
;
import
static
org
.
mockito
.
Mockito
.
anyString
;
import
static
org
.
mockito
.
Mockito
.
mock
;
import
static
org
.
mockito
.
Mockito
.
times
;
import
static
org
.
mockito
.
Mockito
.
verify
;
import
static
org
.
mockito
.
Mockito
.
when
;
@RunWith
(
MockitoJUnitRunner
.
class
)
public
class
AutocompleteChannelInteractorTest
{
...
...
rocket-chat-core/src/test/java/chat/rocket/core/interactors/EditMessageInteractorTest.kt
View file @
5bbd3f7f
...
...
@@ -6,12 +6,14 @@ import chat.rocket.core.models.Message
import
chat.rocket.core.models.PublicSetting
import
chat.rocket.core.models.Room
import
chat.rocket.core.models.User
import
chat.rocket.core.repositories.*
import
chat.rocket.core.repositories.MessageRepository
import
chat.rocket.core.repositories.PublicSettingRepository
import
chat.rocket.core.repositories.RoomRepository
import
chat.rocket.core.repositories.UserRepository
import
com.hadisatrio.optional.Optional
import
io.reactivex.Flowable
import
io.reactivex.Single
import
io.reactivex.observers.TestObserver
import
org.junit.Before
import
org.junit.Test
import
org.junit.runner.RunWith
...
...
rocket-chat-core/src/test/java/chat/rocket/core/interactors/PermissionInteractorTest.kt
View file @
5bbd3f7f
...
...
@@ -8,12 +8,12 @@ import com.hadisatrio.optional.Optional
import
io.reactivex.Flowable
import
io.reactivex.Single
import
io.reactivex.observers.TestObserver
import
org.junit.Before
import
org.junit.Test
import
org.junit.runner.RunWith
import
org.mockito.Mock
import
org.mockito.Mockito.*
import
org.mockito.Mockito.`when`
import
org.mockito.Mockito.any
import
org.mockito.junit.MockitoJUnitRunner
@RunWith
(
MockitoJUnitRunner
::
class
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment