通知用のPendingIntentを作る時に毎回異なるuriを指定する
This commit is contained in:
parent
31fa437fc5
commit
7f4b93dc38
@ -18,8 +18,6 @@ class ActCallback : AppCompatActivity() {
|
|||||||
companion object {
|
companion object {
|
||||||
private val log = LogCategory("ActCallback")
|
private val log = LogCategory("ActCallback")
|
||||||
|
|
||||||
const val ACTION_NOTIFICATION_CLICK = "notification_click"
|
|
||||||
|
|
||||||
internal val last_uri = AtomicReference<Uri>(null)
|
internal val last_uri = AtomicReference<Uri>(null)
|
||||||
internal val sent_intent = AtomicReference<Intent>(null)
|
internal val sent_intent = AtomicReference<Intent>(null)
|
||||||
|
|
||||||
|
@ -1815,9 +1815,11 @@ class ActMain : AppCompatActivity()
|
|||||||
// subwaytooter://notification_click/?db_id=(db_id)
|
// subwaytooter://notification_click/?db_id=(db_id)
|
||||||
val dataIdString = uri.getQueryParameter("db_id")
|
val dataIdString = uri.getQueryParameter("db_id")
|
||||||
if(dataIdString != null) {
|
if(dataIdString != null) {
|
||||||
|
|
||||||
|
PollingWorker.queueNotificationClicked(this, uri)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val dataId = dataIdString.toLong(10)
|
val dataId = dataIdString.toLong()
|
||||||
val type = uri.getQueryParameter("type") ?: ""
|
|
||||||
val account = SavedAccount.loadAccount(this@ActMain, dataId)
|
val account = SavedAccount.loadAccount(this@ActMain, dataId)
|
||||||
if(account != null) {
|
if(account != null) {
|
||||||
var column = app_state.column_list.firstOrNull {
|
var column = app_state.column_list.firstOrNull {
|
||||||
@ -1836,14 +1838,10 @@ class ActMain : AppCompatActivity()
|
|||||||
ColumnType.NOTIFICATIONS
|
ColumnType.NOTIFICATIONS
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 通知を読み直す
|
// 通知を読み直す
|
||||||
if(! column.bInitialLoading) {
|
if(! column.bInitialLoading) {
|
||||||
column.startLoading()
|
column.startLoading()
|
||||||
}
|
}
|
||||||
|
|
||||||
PollingWorker.queueNotificationClicked(this, dataId, type)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch(ex : Throwable) {
|
} catch(ex : Throwable) {
|
||||||
log.trace(ex)
|
log.trace(ex)
|
||||||
|
@ -22,13 +22,8 @@ class EventReceiver : BroadcastReceiver() {
|
|||||||
Intent.ACTION_MY_PACKAGE_REPLACED ->
|
Intent.ACTION_MY_PACKAGE_REPLACED ->
|
||||||
PollingWorker.queuePackageReplaced(context)
|
PollingWorker.queuePackageReplaced(context)
|
||||||
|
|
||||||
ACTION_NOTIFICATION_DELETE -> {
|
ACTION_NOTIFICATION_DELETE ->
|
||||||
PollingWorker.queueNotificationDeleted(
|
PollingWorker.queueNotificationDeleted( context,intent.data)
|
||||||
context,
|
|
||||||
intent.getLongExtra(PollingWorker.EXTRA_DB_ID, - 1L),
|
|
||||||
intent.getStringExtra(PollingWorker.EXTRA_NOTIFICATION_TYPE) ?: ""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> log.e("onReceive: unsupported action %s", action)
|
else -> log.e("onReceive: unsupported action %s", action)
|
||||||
}
|
}
|
||||||
|
@ -81,6 +81,7 @@ class PollingWorker private constructor(contextArg : Context) {
|
|||||||
const val EXTRA_TAG = "tag"
|
const val EXTRA_TAG = "tag"
|
||||||
const val EXTRA_TASK_ID = "task_id"
|
const val EXTRA_TASK_ID = "task_id"
|
||||||
const val EXTRA_NOTIFICATION_TYPE = "notification_type"
|
const val EXTRA_NOTIFICATION_TYPE = "notification_type"
|
||||||
|
const val EXTRA_NOTIFICATION_ID = "notificationId"
|
||||||
|
|
||||||
const val APP_SERVER = "https://mastodon-msg.juggler.jp"
|
const val APP_SERVER = "https://mastodon-msg.juggler.jp"
|
||||||
|
|
||||||
@ -303,26 +304,37 @@ class PollingWorker private constructor(contextArg : Context) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun queueNotificationDeleted(context : Context, db_id : Long, trackingType : String) {
|
private fun decodeNotificationUri(uri:Uri?):JsonObject?{
|
||||||
|
uri ?: return null
|
||||||
|
return jsonObject {
|
||||||
|
putNotNull(
|
||||||
|
EXTRA_DB_ID,
|
||||||
|
uri.getQueryParameter("db_id")?.toLongOrNull()
|
||||||
|
)
|
||||||
|
putNotNull(
|
||||||
|
EXTRA_NOTIFICATION_TYPE,
|
||||||
|
uri.getQueryParameter("type")?.notEmpty()
|
||||||
|
)
|
||||||
|
putNotNull(
|
||||||
|
EXTRA_NOTIFICATION_ID,
|
||||||
|
uri.getQueryParameter("notificationId")?.notEmpty()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun queueNotificationDeleted(context : Context, uri : Uri?) {
|
||||||
try {
|
try {
|
||||||
val data = jsonObject {
|
val params = decodeNotificationUri(uri) ?: return
|
||||||
putNotNull(EXTRA_DB_ID, db_id)
|
addTask(context,false,TASK_NOTIFICATION_DELETE,params)
|
||||||
putNotNull(EXTRA_NOTIFICATION_TYPE, trackingType)
|
|
||||||
}
|
|
||||||
addTask(context, true, TASK_NOTIFICATION_DELETE, data)
|
|
||||||
} catch(ex : JsonException) {
|
} catch(ex : JsonException) {
|
||||||
log.trace(ex)
|
log.trace(ex)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun queueNotificationClicked(context : Context, db_id : Long, trackingType : String) {
|
fun queueNotificationClicked(context : Context, uri:Uri?) {
|
||||||
try {
|
try {
|
||||||
val data = jsonObject {
|
val params = decodeNotificationUri(uri) ?: return
|
||||||
putNotNull(EXTRA_DB_ID, db_id)
|
addTask(context, true, TASK_NOTIFICATION_CLICK, params)
|
||||||
putNotNull(EXTRA_NOTIFICATION_TYPE, trackingType)
|
|
||||||
}
|
|
||||||
addTask(context, true, TASK_NOTIFICATION_CLICK, data)
|
|
||||||
} catch(ex : JsonException) {
|
} catch(ex : JsonException) {
|
||||||
log.trace(ex)
|
log.trace(ex)
|
||||||
}
|
}
|
||||||
@ -815,6 +827,12 @@ class PollingWorker private constructor(contextArg : Context) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun TrackingType.trackingTypeName()=when(this){
|
||||||
|
TrackingType.NotReply ->NotificationHelper.TRACKING_NAME_DEFAULT
|
||||||
|
TrackingType.Reply -> NotificationHelper.TRACKING_NAME_REPLY
|
||||||
|
TrackingType.All -> NotificationHelper.TRACKING_NAME_DEFAULT
|
||||||
|
}
|
||||||
|
|
||||||
internal inner class TaskRunner {
|
internal inner class TaskRunner {
|
||||||
|
|
||||||
lateinit var job : JobItem
|
lateinit var job : JobItem
|
||||||
@ -822,6 +840,8 @@ class PollingWorker private constructor(contextArg : Context) {
|
|||||||
|
|
||||||
val error_instance = ArrayList<String>()
|
val error_instance = ArrayList<String>()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fun runTask(job : JobItem, taskId : Int, taskData : JsonObject) {
|
fun runTask(job : JobItem, taskId : Int, taskData : JsonObject) {
|
||||||
try {
|
try {
|
||||||
log.d("(runTask: taskId=${taskId}")
|
log.d("(runTask: taskId=${taskId}")
|
||||||
@ -910,32 +930,36 @@ class PollingWorker private constructor(contextArg : Context) {
|
|||||||
|
|
||||||
TASK_NOTIFICATION_DELETE -> {
|
TASK_NOTIFICATION_DELETE -> {
|
||||||
val db_id = taskData.long(EXTRA_DB_ID)
|
val db_id = taskData.long(EXTRA_DB_ID)
|
||||||
val type =
|
val type = TrackingType.parseStr(taskData.string(EXTRA_NOTIFICATION_TYPE))
|
||||||
when(TrackingType.parseStr(taskData.string(EXTRA_NOTIFICATION_TYPE))) {
|
val typeName = type.trackingTypeName()
|
||||||
TrackingType.Reply -> NotificationHelper.TRACKING_NAME_REPLY
|
val id = taskData.string(EXTRA_NOTIFICATION_ID)
|
||||||
else -> NotificationHelper.TRACKING_NAME_DEFAULT
|
log.d("Notification deleted! db_id=$db_id,type=$type,id=$id")
|
||||||
}
|
|
||||||
log.d("Notification deleted! db_id=$db_id,type=$type")
|
|
||||||
if(db_id != null) {
|
if(db_id != null) {
|
||||||
NotificationTracking.updateRead(db_id, type)
|
NotificationTracking.updateRead(db_id, typeName)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
TASK_NOTIFICATION_CLICK -> {
|
TASK_NOTIFICATION_CLICK -> {
|
||||||
val db_id = taskData.long(EXTRA_DB_ID)
|
val db_id = taskData.long(EXTRA_DB_ID)
|
||||||
val type =
|
val type = TrackingType.parseStr(taskData.string(EXTRA_NOTIFICATION_TYPE))
|
||||||
when(TrackingType.parseStr(taskData.string(EXTRA_NOTIFICATION_TYPE))) {
|
val typeName = type.trackingTypeName()
|
||||||
TrackingType.Reply -> NotificationHelper.TRACKING_NAME_REPLY
|
val id = taskData.string(EXTRA_NOTIFICATION_ID).notEmpty()
|
||||||
else -> NotificationHelper.TRACKING_NAME_DEFAULT
|
log.d("Notification clicked! db_id=$db_id,type=$type,id=$id")
|
||||||
}
|
|
||||||
log.d("Notification clicked! db_id=$db_id,type=$type")
|
|
||||||
if(db_id != null) {
|
if(db_id != null) {
|
||||||
// 通知をキャンセル
|
// 通知をキャンセル
|
||||||
notification_manager.cancel(db_id.toString(), NOTIFICATION_ID)
|
val notification_tag = when(typeName) {
|
||||||
|
"" -> "${db_id}/_"
|
||||||
|
else -> "${db_id}/$typeName"
|
||||||
|
}
|
||||||
|
if( id != null){
|
||||||
|
val itemTag = "$notification_tag/$id"
|
||||||
|
notification_manager.cancel(itemTag, NOTIFICATION_ID)
|
||||||
|
}else{
|
||||||
|
notification_manager.cancel(notification_tag, NOTIFICATION_ID)
|
||||||
|
}
|
||||||
// DB更新処理
|
// DB更新処理
|
||||||
NotificationTracking.updateRead(db_id, type)
|
NotificationTracking.updateRead(db_id, typeName)
|
||||||
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1276,7 +1300,7 @@ class PollingWorker private constructor(contextArg : Context) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
createNotification(itemTag) { builder ->
|
createNotification(itemTag,notificationId = item.notification.id.toString()) { builder ->
|
||||||
|
|
||||||
val myAcct = item.access_info.acct
|
val myAcct = item.access_info.acct
|
||||||
|
|
||||||
@ -1292,7 +1316,7 @@ class PollingWorker private constructor(contextArg : Context) {
|
|||||||
.setSummaryText(myAcct)
|
.setSummaryText(myAcct)
|
||||||
.bigText(content)
|
.bigText(content)
|
||||||
)
|
)
|
||||||
}else{
|
} else {
|
||||||
builder.setContentText(myAcct)
|
builder.setContentText(myAcct)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1427,54 +1451,11 @@ class PollingWorker private constructor(contextArg : Context) {
|
|||||||
|
|
||||||
private fun createNotification(
|
private fun createNotification(
|
||||||
notification_tag : String,
|
notification_tag : String,
|
||||||
|
notificationId : String? = null,
|
||||||
setContent : (builder : NotificationCompat.Builder) -> Unit
|
setContent : (builder : NotificationCompat.Builder) -> Unit
|
||||||
) {
|
) {
|
||||||
log.d("showNotification[${account.acct}] creating notification(1)")
|
log.d("showNotification[${account.acct}] creating notification(1)")
|
||||||
|
|
||||||
val midInt = Int.MAX_VALUE shr 1
|
|
||||||
|
|
||||||
// 通知タップ時のPendingIntent
|
|
||||||
val intent_click = Intent(context, ActCallback::class.java)
|
|
||||||
intent_click.action = ActCallback.ACTION_NOTIFICATION_CLICK
|
|
||||||
intent_click.data =
|
|
||||||
"subwaytooter://notification_click/?db_id=${account.db_id}&type=${trackingType.str}"
|
|
||||||
.toUri()
|
|
||||||
|
|
||||||
// FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY を付与してはいけない
|
|
||||||
intent_click.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
|
|
||||||
val pi_click = PendingIntent.getActivity(
|
|
||||||
context,
|
|
||||||
when(trackingType) {
|
|
||||||
TrackingType.Reply -> midInt + account.db_id.toInt()
|
|
||||||
else -> 256 + account.db_id.toInt()
|
|
||||||
},
|
|
||||||
intent_click,
|
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT
|
|
||||||
)
|
|
||||||
|
|
||||||
// 通知を消去した時のPendingIntent
|
|
||||||
val intent_delete = Intent(context, EventReceiver::class.java)
|
|
||||||
intent_delete.action = EventReceiver.ACTION_NOTIFICATION_DELETE
|
|
||||||
intent_delete.putExtra(EXTRA_DB_ID, account.db_id)
|
|
||||||
intent_delete.putExtra(EXTRA_NOTIFICATION_TYPE, trackingType.str)
|
|
||||||
val pi_delete = PendingIntent.getBroadcast(
|
|
||||||
context,
|
|
||||||
when(trackingType) {
|
|
||||||
TrackingType.Reply -> {
|
|
||||||
midInt - account.db_id.toInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
Integer.MAX_VALUE - account.db_id.toInt()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
intent_delete,
|
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT
|
|
||||||
)
|
|
||||||
|
|
||||||
log.d("showNotification[${account.acct}] creating notification(2)")
|
|
||||||
|
|
||||||
val builder = if(Build.VERSION.SDK_INT >= 26) {
|
val builder = if(Build.VERSION.SDK_INT >= 26) {
|
||||||
// Android 8 から、通知のスタイルはユーザが管理することになった
|
// Android 8 から、通知のスタイルはユーザが管理することになった
|
||||||
// NotificationChannel を端末に登録しておけば、チャネルごとに管理画面が作られる
|
// NotificationChannel を端末に登録しておけば、チャネルごとに管理画面が作られる
|
||||||
@ -1488,19 +1469,63 @@ class PollingWorker private constructor(contextArg : Context) {
|
|||||||
NotificationCompat.Builder(context, "not_used")
|
NotificationCompat.Builder(context, "not_used")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
builder.apply {
|
||||||
builder.setContentIntent(pi_click)
|
|
||||||
builder.setDeleteIntent(pi_delete)
|
val params = listOf(
|
||||||
builder.setAutoCancel(true)
|
"db_id" to account.db_id.toString(),
|
||||||
builder.setSmallIcon(R.drawable.ic_notification) // ここは常に白テーマのアイコンを使う
|
"type" to trackingType.str,
|
||||||
|
"notificationId" to notificationId
|
||||||
// ここは常に白テーマの色を使う
|
).mapNotNull{
|
||||||
builder.color = ContextCompat.getColor(context, R.color.Light_colorAccent)
|
val second = it.second
|
||||||
|
if( second == null ){
|
||||||
// Android 7.0 ではグループを指定しないと勝手に通知が束ねられてしまう。
|
null
|
||||||
// 束ねられた通知をタップしても pi_click が実行されないので困るため、
|
}else{
|
||||||
// アカウント別にグループキーを設定する
|
"${it.first.encodePercent()}=${second.encodePercent()}"
|
||||||
builder.setGroup(context.packageName + ":" + account.acct)
|
}
|
||||||
|
}.joinToString("&")
|
||||||
|
|
||||||
|
setContentIntent(
|
||||||
|
PendingIntent.getActivity(
|
||||||
|
context,
|
||||||
|
257,
|
||||||
|
Intent(context, ActCallback::class.java).apply {
|
||||||
|
data =
|
||||||
|
"subwaytooter://notification_click/?$params".toUri()
|
||||||
|
|
||||||
|
// FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY を付与してはいけない
|
||||||
|
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
},
|
||||||
|
PendingIntent.FLAG_UPDATE_CURRENT
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
setDeleteIntent(
|
||||||
|
PendingIntent.getBroadcast(
|
||||||
|
context,
|
||||||
|
257,
|
||||||
|
Intent(context, EventReceiver::class.java).apply {
|
||||||
|
action = EventReceiver.ACTION_NOTIFICATION_DELETE
|
||||||
|
data =
|
||||||
|
"subwaytooter://notification_delete/?$params".toUri()
|
||||||
|
},
|
||||||
|
PendingIntent.FLAG_UPDATE_CURRENT
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
setAutoCancel(true)
|
||||||
|
|
||||||
|
// 常に白テーマのアイコンを使う
|
||||||
|
setSmallIcon(R.drawable.ic_notification)
|
||||||
|
|
||||||
|
// 常に白テーマの色を使う
|
||||||
|
builder.color = ContextCompat.getColor(context, R.color.Light_colorAccent)
|
||||||
|
|
||||||
|
// Android 7.0 ではグループを指定しないと勝手に通知が束ねられてしまう。
|
||||||
|
// 束ねられた通知をタップしても pi_click が実行されないので困るため、
|
||||||
|
// アカウント別にグループキーを設定する
|
||||||
|
setGroup(context.packageName + ":" + account.acct)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
log.d("showNotification[${account.acct}] creating notification(3)")
|
log.d("showNotification[${account.acct}] creating notification(3)")
|
||||||
|
|
||||||
@ -1648,5 +1673,4 @@ class PollingWorker private constructor(contextArg : Context) {
|
|||||||
}
|
}
|
||||||
notification_manager.notify(NOTIFICATION_ID_ERROR, builder.build())
|
notification_manager.notify(NOTIFICATION_ID_ERROR, builder.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -11,6 +11,7 @@ import okhttp3.Response
|
|||||||
import okhttp3.WebSocket
|
import okhttp3.WebSocket
|
||||||
import okhttp3.WebSocketListener
|
import okhttp3.WebSocketListener
|
||||||
import java.net.ProtocolException
|
import java.net.ProtocolException
|
||||||
|
import java.net.SocketException
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
import java.util.concurrent.atomic.AtomicReference
|
import java.util.concurrent.atomic.AtomicReference
|
||||||
@ -340,7 +341,11 @@ internal class StreamReader(
|
|||||||
* listener will be made.
|
* listener will be made.
|
||||||
*/
|
*/
|
||||||
override fun onFailure(webSocket : WebSocket, t : Throwable, response : Response?) {
|
override fun onFailure(webSocket : WebSocket, t : Throwable, response : Response?) {
|
||||||
log.e(t, "WebSocket onFailure. url=%s .", webSocket.request().url)
|
if( t is SocketException && t.message == "Socket is closed"){
|
||||||
|
log.w("WebSocket is closed. url=${webSocket.request().url}")
|
||||||
|
}else {
|
||||||
|
log.e(t, "WebSocket onFailure. url=${webSocket.request().url}")
|
||||||
|
}
|
||||||
|
|
||||||
bListening.set(false)
|
bListening.set(false)
|
||||||
handler.removeCallbacks(proc_reconnect)
|
handler.removeCallbacks(proc_reconnect)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user