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
aa0f574b
Commit
aa0f574b
authored
Apr 06, 2018
by
Leonardo Aramaki
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement direct reply on Android N and above
parent
6f0cc896
Changes
8
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
285 additions
and
54 deletions
+285
-54
AndroidManifest.xml
app/src/main/AndroidManifest.xml
+9
-0
ReceiverBuilder.kt
...java/chat/rocket/android/dagger/module/ReceiverBuilder.kt
+5
-0
DirectReplyReceiver.kt
...main/java/chat/rocket/android/push/DirectReplyReceiver.kt
+87
-0
DirectReplyReceiverProvider.kt
...a/chat/rocket/android/push/DirectReplyReceiverProvider.kt
+11
-0
PushManager.kt
app/src/main/java/chat/rocket/android/push/PushManager.kt
+158
-54
strings.xml
app/src/main/res/values-hi-rIN/strings.xml
+5
-0
strings.xml
app/src/main/res/values-pt-rBR/strings.xml
+5
-0
strings.xml
app/src/main/res/values/strings.xml
+5
-0
No files found.
app/src/main/AndroidManifest.xml
View file @
aa0f574b
...
...
@@ -85,6 +85,15 @@
</intent-filter>
</receiver>
<receiver
android:name=
".push.DirectReplyReceiver"
android:enabled=
"true"
android:exported=
"false"
>
<intent-filter>
<action
android:name=
"chat.rocket.android.ACTION_REPLY"
/>
</intent-filter>
</receiver>
<service
android:name=
".push.FirebaseTokenService"
android:exported=
"false"
>
...
...
app/src/main/java/chat/rocket/android/dagger/module/ReceiverBuilder.kt
View file @
aa0f574b
package
chat.rocket.android.dagger.module
import
chat.rocket.android.push.DeleteReceiver
import
chat.rocket.android.push.DirectReplyReceiver
import
chat.rocket.android.push.DirectReplyReceiverProvider
import
chat.rocket.android.push.di.DeleteReceiverProvider
import
dagger.Module
import
dagger.android.ContributesAndroidInjector
...
...
@@ -10,4 +12,7 @@ abstract class ReceiverBuilder {
@ContributesAndroidInjector
(
modules
=
[
DeleteReceiverProvider
::
class
])
abstract
fun
bindDeleteReceiver
():
DeleteReceiver
@ContributesAndroidInjector
(
modules
=
[
DirectReplyReceiverProvider
::
class
])
abstract
fun
bindDirectReplyReceiver
():
DirectReplyReceiver
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/push/DirectReplyReceiver.kt
0 → 100644
View file @
aa0f574b
package
chat.rocket.android.push
import
android.app.NotificationManager
import
android.content.BroadcastReceiver
import
android.content.Context
import
android.content.Intent
import
android.support.v4.app.RemoteInput
import
android.widget.Toast
import
chat.rocket.android.R
import
chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import
chat.rocket.common.RocketChatException
import
chat.rocket.core.internal.rest.sendMessage
import
dagger.android.AndroidInjection
import
kotlinx.coroutines.experimental.android.UI
import
kotlinx.coroutines.experimental.launch
import
timber.log.Timber
import
java.util.*
import
javax.inject.Inject
/**
* BroadcastReceiver for direct reply on notifications.
*/
class
DirectReplyReceiver
:
BroadcastReceiver
()
{
@Inject
lateinit
var
factory
:
ConnectionManagerFactory
@Inject
lateinit
var
groupedPushes
:
GroupedPush
override
fun
onReceive
(
context
:
Context
,
intent
:
Intent
)
{
AndroidInjection
.
inject
(
this
,
context
)
if
(
ACTION_REPLY
==
intent
.
action
)
{
val
message
=
intent
.
getParcelableExtra
<
PushMessage
>(
EXTRA_PUSH_MESSAGE
)
message
?.
let
{
launch
(
UI
)
{
try
{
println
(
it
)
sendMessage
(
it
,
extractReplyMessage
(
intent
))
val
manager
=
context
.
getSystemService
(
Context
.
NOTIFICATION_SERVICE
)
as
NotificationManager
clearNotificationsByHostAndNotificationId
(
it
.
info
.
host
,
it
.
notificationId
.
toInt
())
manager
.
cancel
(
it
.
notificationId
.
toInt
())
val
feedback
=
context
.
getString
(
R
.
string
.
notif_success_sending
,
it
.
title
)
Toast
.
makeText
(
context
,
feedback
,
Toast
.
LENGTH_SHORT
).
show
()
}
catch
(
ex
:
RocketChatException
)
{
Timber
.
e
(
ex
)
val
feedback
=
context
.
getString
(
R
.
string
.
notif_error_sending
)
Toast
.
makeText
(
context
,
feedback
,
Toast
.
LENGTH_SHORT
).
show
()
}
}
}
}
}
private
suspend
fun
sendMessage
(
message
:
PushMessage
,
replyText
:
CharSequence
?)
{
replyText
?.
let
{
reply
->
val
currentServer
=
message
.
info
.
hostname
val
roomId
=
message
.
info
.
roomId
val
connectionManager
=
factory
.
create
(
currentServer
)
val
client
=
connectionManager
.
client
val
id
=
UUID
.
randomUUID
().
toString
()
client
.
sendMessage
(
id
,
roomId
,
reply
.
toString
())
// Do we need to disconnect here?
}
}
private
fun
extractReplyMessage
(
intent
:
Intent
):
CharSequence
?
{
val
bundle
=
RemoteInput
.
getResultsFromIntent
(
intent
)
if
(
bundle
!=
null
)
{
return
bundle
.
getCharSequence
(
REMOTE_INPUT_REPLY
)
}
return
null
}
/**
* Clear notifications by the host they belong to and its unique id.
*/
private
fun
clearNotificationsByHostAndNotificationId
(
host
:
String
,
notificationId
:
Int
)
{
if
(
groupedPushes
.
hostToPushMessageList
.
isNotEmpty
())
{
val
notifications
=
groupedPushes
.
hostToPushMessageList
[
host
]
notifications
?.
let
{
notifications
.
removeAll
{
it
.
notificationId
.
toInt
()
==
notificationId
}
}
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/push/DirectReplyReceiverProvider.kt
0 → 100644
View file @
aa0f574b
package
chat.rocket.android.push
import
chat.rocket.android.dagger.module.AppModule
import
dagger.Module
import
dagger.android.ContributesAndroidInjector
@Module
abstract
class
DirectReplyReceiverProvider
{
@ContributesAndroidInjector
(
modules
=
[
AppModule
::
class
])
abstract
fun
provideDirectReplyReceiver
():
DirectReplyReceiver
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/push/PushManager.kt
View file @
aa0f574b
...
...
@@ -7,9 +7,13 @@ import android.app.NotificationManager
import
android.app.PendingIntent
import
android.content.Context
import
android.content.Intent
import
android.content.IntentFilter
import
android.graphics.drawable.Icon
import
android.media.RingtoneManager
import
android.os.Build
import
android.os.Bundle
import
android.os.Parcel
import
android.os.Parcelable
import
android.support.annotation.RequiresApi
import
android.support.v4.app.NotificationCompat
import
android.support.v4.app.NotificationManagerCompat
...
...
@@ -17,16 +21,17 @@ import android.support.v4.app.RemoteInput
import
android.text.Html
import
android.text.Spanned
import
chat.rocket.android.R
import
chat.rocket.android.main.ui.MainActivity
import
chat.rocket.android.server.domain.GetAccountInteractor
import
chat.rocket.android.server.domain.GetSettingsInteractor
import
chat.rocket.android.server.domain.siteName
import
chat.rocket.android.server.ui.changeServerIntent
import
chat.rocket.common.model.RoomType
import
chat.rocket.common.model.roomTypeOf
import
com.squareup.moshi.Json
import
com.squareup.moshi.Moshi
import
kotlinx.coroutines.experimental.runBlocking
import
se.ansman.kotshi.JsonSerializable
import
se.ansman.kotshi.KotshiConstructor
import
timber.log.Timber
import
java.util.*
import
java.util.concurrent.atomic.AtomicInteger
...
...
@@ -209,7 +214,8 @@ class PushManager @Inject constructor(
builder
.
setStyle
(
bigTextStyle
)
}
return
builder
.
build
()
return
builder
.
addReplyAction
(
pushMessage
)
.
build
()
}
}
...
...
@@ -282,40 +288,49 @@ class PushManager @Inject constructor(
//Notification.Builder extensions
@RequiresApi
(
Build
.
VERSION_CODES
.
N
)
private
fun
Notification
.
Builder
.
addReplyAction
(
pushMessage
:
PushMessage
):
Notification
.
Builder
{
val
replyTextHint
=
context
.
getText
(
R
.
string
.
notif_action_reply_hint
)
val
replyRemoteInput
=
android
.
app
.
RemoteInput
.
Builder
(
REMOTE_INPUT_REPLY
)
.
setLabel
(
REPLY_LABEL
)
.
setLabel
(
replyTextHint
)
.
build
()
//TODO: Implement this when we have sendMessage call
// 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 =
// Notification.Action.Builder(
// Icon.createWithResource(context, R.drawable.ic_reply), REPLY_LABEL, pendingIntent)
// .addRemoteInput(replyRemoteInput)
// .setAllowGeneratedReplies(true)
// .build()
// this.addAction(replyAction)
val
replyIntent
=
Intent
(
context
,
DirectReplyReceiver
::
class
.
java
)
replyIntent
.
action
=
ACTION_REPLY
replyIntent
.
putExtra
(
EXTRA_PUSH_MESSAGE
,
pushMessage
as
Parcelable
)
val
filter
=
IntentFilter
().
apply
{
addAction
(
ACTION_REPLY
)
}
val
pendingIntent
=
PendingIntent
.
getBroadcast
(
context
,
randomizer
.
nextInt
(),
replyIntent
,
PendingIntent
.
FLAG_UPDATE_CURRENT
)
val
replyAction
=
Notification
.
Action
.
Builder
(
Icon
.
createWithResource
(
context
,
R
.
drawable
.
ic_reply_black_24px
),
replyTextHint
,
pendingIntent
)
.
addRemoteInput
(
replyRemoteInput
)
.
setAllowGeneratedReplies
(
true
)
.
build
()
this
.
addAction
(
replyAction
)
return
this
}
// NotificationCompat.Builder extensions
private
fun
NotificationCompat
.
Builder
.
addReplyAction
(
pushMessage
:
PushMessage
):
NotificationCompat
.
Builder
{
val
replyTextHint
=
context
.
getText
(
R
.
string
.
notif_action_reply_hint
)
val
replyRemoteInput
=
RemoteInput
.
Builder
(
REMOTE_INPUT_REPLY
)
.
setLabel
(
REPLY_LABEL
)
.
setLabel
(
replyTextHint
)
.
build
()
//TODO: Implement when we have sendMessage call
// 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)
val
replyIntent
=
Intent
(
context
,
DirectReplyReceiver
::
class
.
java
)
replyIntent
.
action
=
ACTION_REPLY
replyIntent
.
putExtra
(
EXTRA_PUSH_MESSAGE
,
pushMessage
as
Parcelable
)
val
filter
=
IntentFilter
().
apply
{
addAction
(
ACTION_REPLY
)
}
val
pendingIntent
=
PendingIntent
.
getBroadcast
(
context
,
randomizer
.
nextInt
(),
replyIntent
,
PendingIntent
.
FLAG_UPDATE_CURRENT
)
val
replyAction
=
NotificationCompat
.
Action
.
Builder
(
R
.
drawable
.
ic_reply_black_24px
,
replyTextHint
,
pendingIntent
)
.
addRemoteInput
(
replyRemoteInput
)
.
setAllowGeneratedReplies
(
true
)
.
build
()
this
.
addAction
(
replyAction
)
return
this
}
...
...
@@ -345,22 +360,64 @@ data class PushMessage(
val
notificationId
:
String
,
val
summaryText
:
String
?
=
null
,
val
style
:
String
?
=
null
)
)
:
Parcelable
{
constructor
(
parcel
:
Parcel
)
:
this
(
parcel
.
readString
(),
parcel
.
readString
(),
parcel
.
readParcelable
(
PushMessage
::
class
.
java
.
classLoader
),
parcel
.
readString
(),
parcel
.
readString
(),
parcel
.
readString
(),
parcel
.
readString
(),
parcel
.
readString
())
override
fun
writeToParcel
(
parcel
:
Parcel
,
flags
:
Int
)
{
parcel
.
writeString
(
title
)
parcel
.
writeString
(
message
)
parcel
.
writeParcelable
(
info
,
flags
)
parcel
.
writeString
(
image
)
parcel
.
writeString
(
count
)
parcel
.
writeString
(
notificationId
)
parcel
.
writeString
(
summaryText
)
parcel
.
writeString
(
style
)
}
override
fun
describeContents
():
Int
{
return
0
}
companion
object
CREATOR
:
Parcelable
.
Creator
<
PushMessage
>
{
override
fun
createFromParcel
(
parcel
:
Parcel
):
PushMessage
{
return
PushMessage
(
parcel
)
}
override
fun
newArray
(
size
:
Int
):
Array
<
PushMessage
?
>
{
return
arrayOfNulls
(
size
)
}
}
}
@JsonSerializable
data class
PushInfo
(
data class
PushInfo
@KotshiConstructor
constructor
(
@Json
(
name
=
"host"
)
val
hostname
:
String
,
@Json
(
name
=
"rid"
)
val
roomId
:
String
,
val
type
:
RoomType
,
val
name
:
String
?,
val
sender
:
PushSender
?
)
{
)
:
Parcelable
{
val
createdAt
:
Long
get
()
=
System
.
currentTimeMillis
()
val
host
by
lazy
{
sanitizeUrl
(
hostname
)
}
constructor
(
parcel
:
Parcel
)
:
this
(
parcel
.
readString
(),
parcel
.
readString
(),
roomTypeOf
(
parcel
.
readString
()),
parcel
.
readString
(),
parcel
.
readParcelable
(
PushInfo
::
class
.
java
.
classLoader
))
private
fun
sanitizeUrl
(
baseUrl
:
String
):
String
{
var
url
=
baseUrl
.
trim
()
while
(
url
.
endsWith
(
'/'
))
{
...
...
@@ -369,18 +426,65 @@ data class PushInfo(
return
url
}
override
fun
writeToParcel
(
parcel
:
Parcel
,
flags
:
Int
)
{
parcel
.
writeString
(
hostname
)
parcel
.
writeString
(
roomId
)
parcel
.
writeString
(
type
.
toString
())
parcel
.
writeString
(
name
)
parcel
.
writeParcelable
(
sender
,
flags
)
}
override
fun
describeContents
():
Int
{
return
0
}
companion
object
CREATOR
:
Parcelable
.
Creator
<
PushInfo
>
{
override
fun
createFromParcel
(
parcel
:
Parcel
):
PushInfo
{
return
PushInfo
(
parcel
)
}
override
fun
newArray
(
size
:
Int
):
Array
<
PushInfo
?
>
{
return
arrayOfNulls
(
size
)
}
}
}
@JsonSerializable
data class
PushSender
(
data class
PushSender
@KotshiConstructor
constructor
(
@Json
(
name
=
"_id"
)
val
id
:
String
,
val
username
:
String
?,
val
name
:
String
?
)
)
:
Parcelable
{
constructor
(
parcel
:
Parcel
)
:
this
(
parcel
.
readString
(),
parcel
.
readString
(),
parcel
.
readString
())
override
fun
writeToParcel
(
parcel
:
Parcel
,
flags
:
Int
)
{
parcel
.
writeString
(
id
)
parcel
.
writeString
(
username
)
parcel
.
writeString
(
name
)
}
override
fun
describeContents
():
Int
{
return
0
}
companion
object
CREATOR
:
Parcelable
.
Creator
<
PushSender
>
{
override
fun
createFromParcel
(
parcel
:
Parcel
):
PushSender
{
return
PushSender
(
parcel
)
}
override
fun
newArray
(
size
:
Int
):
Array
<
PushSender
?
>
{
return
arrayOfNulls
(
size
)
}
}
}
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"
const
val
ACTION_REPLY
=
"chat.rocket.android.ACTION_
REPLY"
const
val
REMOTE_INPUT_REPLY
=
"REMOTE_INPUT_REPLY"
app/src/main/res/values-hi-rIN/strings.xml
View file @
aa0f574b
...
...
@@ -177,4 +177,9 @@
<string
name=
"header_direct_messages"
>
प्रत्यक्ष संदेश
</string>
<string
name=
"header_live_chats"
>
Live Chats
</string>
<string
name=
"header_unknown"
>
अज्ञात
</string>
<!--Notifications-->
<string
name=
"notif_action_reply_hint"
>
जवाब
</string>
<string
name=
"notif_error_sending"
>
उत्तर विफल हुआ है। कृपया फिर से प्रयास करें।
</string>
<string
name=
"notif_success_sending"
>
संदेश भेजा गया %1$s!
</string>
</resources>
\ No newline at end of file
app/src/main/res/values-pt-rBR/strings.xml
View file @
aa0f574b
...
...
@@ -177,4 +177,9 @@
<string
name=
"header_direct_messages"
>
Mensagens diretas
</string>
<string
name=
"header_live_chats"
>
Live Chats
</string>
<string
name=
"header_unknown"
>
Desconhecido
</string>
<!--Notifications-->
<string
name=
"notif_action_reply_hint"
>
RESPONDER
</string>
<string
name=
"notif_error_sending"
>
Falha ao enviar a mensagem.
</string>
<string
name=
"notif_success_sending"
>
Mensagem enviada para %1$s!
</string>
</resources>
\ No newline at end of file
app/src/main/res/values/strings.xml
View file @
aa0f574b
...
...
@@ -178,4 +178,9 @@
<string
name=
"header_direct_messages"
>
Direct Messages
</string>
<string
name=
"header_live_chats"
>
Live Chats
</string>
<string
name=
"header_unknown"
>
Unknown
</string>
<!--Notifications-->
<string
name=
"notif_action_reply_hint"
>
REPLY
</string>
<string
name=
"notif_error_sending"
>
Reply has failed. Please try again.
</string>
<string
name=
"notif_success_sending"
>
Message sent to %1$s!
</string>
</resources>
\ No newline at end of file
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