1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
package net.taler.wallet.backend
import android.app.Application
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.*
import android.util.Log
import android.util.SparseArray
import org.json.JSONObject
import java.lang.ref.WeakReference
import java.util.*
class WalletBackendApi(private val app: Application) {
private var walletBackendMessenger: Messenger? = null
private val queuedMessages = LinkedList<Message>()
private val handlers = SparseArray<(message: JSONObject) -> Unit>()
private var nextRequestID = 1
var notificationHandler: (() -> Unit)? = null
var connectedHandler: (() -> Unit)? = null
private val walletBackendConn = object : ServiceConnection {
override fun onServiceDisconnected(p0: ComponentName?) {
Log.w(TAG, "wallet backend service disconnected (crash?)")
walletBackendMessenger = null
}
override fun onServiceConnected(componentName: ComponentName?, binder: IBinder?) {
Log.i(TAG, "connected to wallet backend service")
val bm = Messenger(binder)
walletBackendMessenger = bm
pumpQueue(bm)
val msg = Message.obtain(null, WalletBackendService.MSG_SUBSCRIBE_NOTIFY)
msg.replyTo = incomingMessenger
bm.send(msg)
val ch = connectedHandler
if (ch != null) {
ch()
}
}
}
private class IncomingHandler(strongApi: WalletBackendApi) : Handler() {
private val weakApi = WeakReference<WalletBackendApi>(strongApi)
override fun handleMessage(msg: Message) {
val api = weakApi.get() ?: return
when (msg.what) {
WalletBackendService.MSG_REPLY -> {
val requestID = msg.data.getInt("requestID", 0)
val operation = msg.data.getString("operation", "??")
Log.i(TAG, "got reply for operation $operation ($requestID)")
val h = api.handlers.get(requestID)
if (h == null) {
Log.e(TAG, "request ID not associated with a handler")
return
}
val response = msg.data.getString("response")
if (response == null) {
Log.e(TAG, "response did not contain response payload")
return
}
val json = JSONObject(response)
h(json)
}
WalletBackendService.MSG_NOTIFY -> {
val nh = api.notificationHandler
if (nh != null) {
nh()
}
}
}
}
}
private val incomingMessenger = Messenger(IncomingHandler(this))
init {
Intent(app, WalletBackendService::class.java).also { intent ->
app.bindService(intent, walletBackendConn, Context.BIND_AUTO_CREATE)
}
}
private fun pumpQueue(bm: Messenger) {
while (true) {
val msg = queuedMessages.pollFirst() ?: return
bm.send(msg)
}
}
fun sendRequest(
operation: String,
args: JSONObject?,
onResponse: (message: JSONObject) -> Unit = { }
) {
val requestID = nextRequestID++
Log.i(TAG, "sending request for operation $operation ($requestID)")
val msg = Message.obtain(null, WalletBackendService.MSG_COMMAND)
handlers.put(requestID, onResponse)
msg.replyTo = incomingMessenger
val data = msg.data
data.putString("operation", operation)
data.putInt("requestID", requestID)
if (args != null) {
data.putString("args", args.toString())
}
val bm = walletBackendMessenger
if (bm != null) {
bm.send(msg)
} else {
queuedMessages.add(msg)
}
}
fun destroy() {
// FIXME: implement this!
}
companion object {
const val TAG = "WalletBackendApi"
}
}
|