diff options
Diffstat (limited to 'wallet/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt')
-rw-r--r-- | wallet/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/wallet/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt b/wallet/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt new file mode 100644 index 00000000..d447287c --- /dev/null +++ b/wallet/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt @@ -0,0 +1,141 @@ +/* + * This file is part of GNU Taler + * (C) 2020 Taler Systems S.A. + * + * GNU Taler is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 3, or (at your option) any later version. + * + * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + + +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.Handler +import android.os.IBinder +import android.os.Message +import android.os.Messenger +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 val onConnected: (() -> Unit), + private val notificationHandler: (() -> Unit) +) { + + private var walletBackendMessenger: Messenger? = null + private val queuedMessages = LinkedList<Message>() + private val handlers = SparseArray<(isError: Boolean, message: JSONObject) -> Unit>() + private var nextRequestID = 1 + + 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) + onConnected.invoke() + } + } + + private class IncomingHandler(strongApi: WalletBackendApi) : Handler() { + private val weakApi = WeakReference(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 isError = msg.data.getBoolean("isError") + val json = JSONObject(response) + h(isError, json) + } + WalletBackendService.MSG_NOTIFY -> { + api.notificationHandler.invoke() + } + } + } + } + + 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: (isError: Boolean, 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" + } +} |