1
0
mirror of https://github.com/tateisu/SubwayTooter synced 2025-02-07 06:04:23 +01:00

通知用のPendingIntentを作る時に毎回異なるuriを指定する

This commit is contained in:
tateisu 2020-01-16 18:31:14 +09:00
parent 31fa437fc5
commit 7f4b93dc38
5 changed files with 125 additions and 105 deletions

View File

@ -18,8 +18,6 @@ class ActCallback : AppCompatActivity() {
companion object {
private val log = LogCategory("ActCallback")
const val ACTION_NOTIFICATION_CLICK = "notification_click"
internal val last_uri = AtomicReference<Uri>(null)
internal val sent_intent = AtomicReference<Intent>(null)

View File

@ -1815,9 +1815,11 @@ class ActMain : AppCompatActivity()
// subwaytooter://notification_click/?db_id=(db_id)
val dataIdString = uri.getQueryParameter("db_id")
if(dataIdString != null) {
PollingWorker.queueNotificationClicked(this, uri)
try {
val dataId = dataIdString.toLong(10)
val type = uri.getQueryParameter("type") ?: ""
val dataId = dataIdString.toLong()
val account = SavedAccount.loadAccount(this@ActMain, dataId)
if(account != null) {
var column = app_state.column_list.firstOrNull {
@ -1836,14 +1838,10 @@ class ActMain : AppCompatActivity()
ColumnType.NOTIFICATIONS
)
}
// 通知を読み直す
if(! column.bInitialLoading) {
column.startLoading()
}
PollingWorker.queueNotificationClicked(this, dataId, type)
}
} catch(ex : Throwable) {
log.trace(ex)

View File

@ -22,13 +22,8 @@ class EventReceiver : BroadcastReceiver() {
Intent.ACTION_MY_PACKAGE_REPLACED ->
PollingWorker.queuePackageReplaced(context)
ACTION_NOTIFICATION_DELETE -> {
PollingWorker.queueNotificationDeleted(
context,
intent.getLongExtra(PollingWorker.EXTRA_DB_ID, - 1L),
intent.getStringExtra(PollingWorker.EXTRA_NOTIFICATION_TYPE) ?: ""
)
}
ACTION_NOTIFICATION_DELETE ->
PollingWorker.queueNotificationDeleted( context,intent.data)
else -> log.e("onReceive: unsupported action %s", action)
}

View File

@ -81,6 +81,7 @@ class PollingWorker private constructor(contextArg : Context) {
const val EXTRA_TAG = "tag"
const val EXTRA_TASK_ID = "task_id"
const val EXTRA_NOTIFICATION_TYPE = "notification_type"
const val EXTRA_NOTIFICATION_ID = "notificationId"
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 {
val data = jsonObject {
putNotNull(EXTRA_DB_ID, db_id)
putNotNull(EXTRA_NOTIFICATION_TYPE, trackingType)
}
addTask(context, true, TASK_NOTIFICATION_DELETE, data)
val params = decodeNotificationUri(uri) ?: return
addTask(context,false,TASK_NOTIFICATION_DELETE,params)
} catch(ex : JsonException) {
log.trace(ex)
}
}
fun queueNotificationClicked(context : Context, db_id : Long, trackingType : String) {
fun queueNotificationClicked(context : Context, uri:Uri?) {
try {
val data = jsonObject {
putNotNull(EXTRA_DB_ID, db_id)
putNotNull(EXTRA_NOTIFICATION_TYPE, trackingType)
}
addTask(context, true, TASK_NOTIFICATION_CLICK, data)
val params = decodeNotificationUri(uri) ?: return
addTask(context, true, TASK_NOTIFICATION_CLICK, params)
} catch(ex : JsonException) {
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 {
lateinit var job : JobItem
@ -822,6 +840,8 @@ class PollingWorker private constructor(contextArg : Context) {
val error_instance = ArrayList<String>()
fun runTask(job : JobItem, taskId : Int, taskData : JsonObject) {
try {
log.d("(runTask: taskId=${taskId}")
@ -910,32 +930,36 @@ class PollingWorker private constructor(contextArg : Context) {
TASK_NOTIFICATION_DELETE -> {
val db_id = taskData.long(EXTRA_DB_ID)
val type =
when(TrackingType.parseStr(taskData.string(EXTRA_NOTIFICATION_TYPE))) {
TrackingType.Reply -> NotificationHelper.TRACKING_NAME_REPLY
else -> NotificationHelper.TRACKING_NAME_DEFAULT
}
log.d("Notification deleted! db_id=$db_id,type=$type")
val type = TrackingType.parseStr(taskData.string(EXTRA_NOTIFICATION_TYPE))
val typeName = type.trackingTypeName()
val id = taskData.string(EXTRA_NOTIFICATION_ID)
log.d("Notification deleted! db_id=$db_id,type=$type,id=$id")
if(db_id != null) {
NotificationTracking.updateRead(db_id, type)
NotificationTracking.updateRead(db_id, typeName)
}
return
}
TASK_NOTIFICATION_CLICK -> {
val db_id = taskData.long(EXTRA_DB_ID)
val type =
when(TrackingType.parseStr(taskData.string(EXTRA_NOTIFICATION_TYPE))) {
TrackingType.Reply -> NotificationHelper.TRACKING_NAME_REPLY
else -> NotificationHelper.TRACKING_NAME_DEFAULT
}
log.d("Notification clicked! db_id=$db_id,type=$type")
val type = TrackingType.parseStr(taskData.string(EXTRA_NOTIFICATION_TYPE))
val typeName = type.trackingTypeName()
val id = taskData.string(EXTRA_NOTIFICATION_ID).notEmpty()
log.d("Notification clicked! db_id=$db_id,type=$type,id=$id")
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更新処理
NotificationTracking.updateRead(db_id, type)
NotificationTracking.updateRead(db_id, typeName)
}
return
}
@ -1276,7 +1300,7 @@ class PollingWorker private constructor(contextArg : Context) {
continue
}
createNotification(itemTag) { builder ->
createNotification(itemTag,notificationId = item.notification.id.toString()) { builder ->
val myAcct = item.access_info.acct
@ -1292,7 +1316,7 @@ class PollingWorker private constructor(contextArg : Context) {
.setSummaryText(myAcct)
.bigText(content)
)
}else{
} else {
builder.setContentText(myAcct)
}
@ -1427,54 +1451,11 @@ class PollingWorker private constructor(contextArg : Context) {
private fun createNotification(
notification_tag : String,
notificationId : String? = null,
setContent : (builder : NotificationCompat.Builder) -> Unit
) {
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) {
// Android 8 から、通知のスタイルはユーザが管理することになった
// NotificationChannel を端末に登録しておけば、チャネルごとに管理画面が作られる
@ -1488,19 +1469,63 @@ class PollingWorker private constructor(contextArg : Context) {
NotificationCompat.Builder(context, "not_used")
}
builder.setContentIntent(pi_click)
builder.setDeleteIntent(pi_delete)
builder.setAutoCancel(true)
builder.setSmallIcon(R.drawable.ic_notification) // ここは常に白テーマのアイコンを使う
// ここは常に白テーマの色を使う
builder.color = ContextCompat.getColor(context, R.color.Light_colorAccent)
// Android 7.0 ではグループを指定しないと勝手に通知が束ねられてしまう。
// 束ねられた通知をタップしても pi_click が実行されないので困るため、
// アカウント別にグループキーを設定する
builder.setGroup(context.packageName + ":" + account.acct)
builder.apply {
val params = listOf(
"db_id" to account.db_id.toString(),
"type" to trackingType.str,
"notificationId" to notificationId
).mapNotNull{
val second = it.second
if( second == null ){
null
}else{
"${it.first.encodePercent()}=${second.encodePercent()}"
}
}.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)")
@ -1648,5 +1673,4 @@ class PollingWorker private constructor(contextArg : Context) {
}
notification_manager.notify(NOTIFICATION_ID_ERROR, builder.build())
}
}

View File

@ -11,6 +11,7 @@ import okhttp3.Response
import okhttp3.WebSocket
import okhttp3.WebSocketListener
import java.net.ProtocolException
import java.net.SocketException
import java.util.*
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicReference
@ -340,7 +341,11 @@ internal class StreamReader(
* listener will be made.
*/
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)
handler.removeCallbacks(proc_reconnect)