diff options
author | Florian Dold <florian.dold@gmail.com> | 2019-12-07 20:48:11 +0100 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2019-12-07 20:48:11 +0100 |
commit | bf3f54de88679e06690f3da35be2543cb121efeb (patch) | |
tree | de1c007eb888508edd0ad33d405bc31e7ef65042 | |
parent | 80cd3c9d6d83798316a1222f3875d3a0e74ca278 (diff) | |
download | wallet-android-bf3f54de88679e06690f3da35be2543cb121efeb.tar.gz wallet-android-bf3f54de88679e06690f3da35be2543cb121efeb.tar.bz2 wallet-android-bf3f54de88679e06690f3da35be2543cb121efeb.zip |
pending ops, various tweaks
-rw-r--r-- | .idea/dictionaries/dold.xml | 1 | ||||
-rw-r--r-- | app/build.gradle | 2 | ||||
-rw-r--r-- | app/src/main/java/net/taler/wallet/HostCardEmulatorService.kt | 104 | ||||
-rw-r--r-- | app/src/main/java/net/taler/wallet/MainActivity.kt | 9 | ||||
-rw-r--r-- | app/src/main/java/net/taler/wallet/PromptPayment.kt | 14 | ||||
-rw-r--r-- | app/src/main/java/net/taler/wallet/ShowBalance.kt | 2 | ||||
-rw-r--r-- | app/src/main/java/net/taler/wallet/WalletHistory.kt | 5 | ||||
-rw-r--r-- | app/src/main/java/net/taler/wallet/WalletViewModel.kt | 36 | ||||
-rw-r--r-- | app/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt | 6 | ||||
-rw-r--r-- | app/src/main/java/net/taler/wallet/backend/WalletBackendService.kt | 102 | ||||
-rw-r--r-- | app/src/main/res/layout/fragment_settings.xml | 4 | ||||
-rw-r--r-- | app/src/main/res/layout/history_row.xml | 7 | ||||
-rw-r--r-- | app/src/main/res/layout/pending_row.xml | 7 | ||||
-rw-r--r-- | app/src/main/res/xml/apduservice.xml | 2 | ||||
-rw-r--r-- | build.gradle | 2 |
15 files changed, 112 insertions, 191 deletions
diff --git a/.idea/dictionaries/dold.xml b/.idea/dictionaries/dold.xml index 67d533a..b258635 100644 --- a/.idea/dictionaries/dold.xml +++ b/.idea/dictionaries/dold.xml @@ -1,6 +1,7 @@ <component name="ProjectDictionaryState"> <dictionary name="dold"> <words> + <w>apdu</w> <w>taler</w> </words> </dictionary> diff --git a/app/build.gradle b/app/build.gradle index 8270882..c98ff94 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,7 +8,7 @@ android { buildToolsVersion "29.0.2" defaultConfig { applicationId "net.taler.wallet" - minSdkVersion 18 + minSdkVersion 21 targetSdkVersion 29 versionCode 2 versionName "0.6.0pre3" diff --git a/app/src/main/java/net/taler/wallet/HostCardEmulatorService.kt b/app/src/main/java/net/taler/wallet/HostCardEmulatorService.kt index cdcf492..b099b74 100644 --- a/app/src/main/java/net/taler/wallet/HostCardEmulatorService.kt +++ b/app/src/main/java/net/taler/wallet/HostCardEmulatorService.kt @@ -1,53 +1,12 @@ package net.taler.wallet -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import android.content.IntentFilter +import android.content.* import android.nfc.cardemulation.HostApduService import android.os.Bundle import android.util.Log import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream -import java.util.* import java.util.concurrent.ConcurrentLinkedDeque -import java.util.concurrent.ConcurrentLinkedQueue - -class Utils { - companion object { - private val HEX_CHARS = "0123456789ABCDEF" - fun hexStringToByteArray(data: String) : ByteArray { - - val result = ByteArray(data.length / 2) - - for (i in 0 until data.length step 2) { - val firstIndex = HEX_CHARS.indexOf(data[i]); - val secondIndex = HEX_CHARS.indexOf(data[i + 1]); - - val octet = firstIndex.shl(4).or(secondIndex) - result.set(i.shr(1), octet.toByte()) - } - - return result - } - - private val HEX_CHARS_ARRAY = "0123456789ABCDEF".toCharArray() - fun toHex(byteArray: ByteArray) : String { - val result = StringBuffer() - - byteArray.forEach { - val octet = it.toInt() - val firstIndex = (octet and 0xF0).ushr(4) - val secondIndex = octet and 0x0F - result.append(HEX_CHARS_ARRAY[firstIndex]) - result.append(HEX_CHARS_ARRAY[secondIndex]) - } - - return result.toString() - } - } -} - fun makeApduSuccessResponse(payload: ByteArray): ByteArray { val stream = ByteArrayOutputStream() @@ -84,19 +43,27 @@ fun readApduBodySize(stream: ByteArrayInputStream): Int { class HostCardEmulatorService: HostApduService() { val queuedRequests: ConcurrentLinkedDeque<String> = ConcurrentLinkedDeque() + lateinit var receiver: BroadcastReceiver override fun onCreate() { + super.onCreate() + receiver = object : BroadcastReceiver() { + override fun onReceive(p0: Context?, p1: Intent?) { + queuedRequests.addLast(p1!!.getStringExtra("tunnelMessage")) + } + } IntentFilter(HTTP_TUNNEL_REQUEST).also { filter -> - registerReceiver(object : BroadcastReceiver() { - override fun onReceive(p0: Context?, p1: Intent?) { - queuedRequests.addLast(p1!!.getStringExtra("tunnelMessage")) - } - }, filter) + registerReceiver(receiver, filter) } } + override fun onDestroy() { + super.onDestroy() + unregisterReceiver(receiver) + } + override fun onDeactivated(reason: Int) { - Log.d(TAG, "Deactivated: " + reason) + Log.d(TAG, "Deactivated: $reason") Intent().also { intent -> intent.action = MERCHANT_NFC_DISCONNECTED sendBroadcast(intent) @@ -106,7 +73,7 @@ class HostCardEmulatorService: HostApduService() { override fun processCommandApdu(commandApdu: ByteArray?, extras: Bundle?): ByteArray { - //Log.d(TAG, "Processing command APDU") + Log.d(TAG, "Processing command APDU") if (commandApdu == null) { Log.d(TAG, "APDU is null") @@ -124,14 +91,9 @@ class HostCardEmulatorService: HostApduService() { val instruction = stream.read() - val instructionStr = "%02x".format(instruction) - - //Log.v(TAG, "Processing instruction $instructionStr") - - val p1 = stream.read() - val p2 = stream.read() - - //Log.v(TAG, "instruction paramaters $p1 $p2") + // Read instruction parameters, currently ignored. + stream.read() + stream.read() if (instruction == SELECT_INS) { // FIXME: validate body! @@ -150,15 +112,16 @@ class HostCardEmulatorService: HostApduService() { if (instruction == PUT_INS) { val bodySize = readApduBodySize(stream) - - val talerInstr = stream.read() val bodyBytes = stream.readBytes() + if (1 + bodyBytes.size != bodySize) { + Log.w(TAG, "mismatched body size ($bodySize vs ${bodyBytes.size}") + } - - when (talerInstr.toInt()) { + when (talerInstr) { 1 -> { val url = String(bodyBytes, Charsets.UTF_8) + Log.v(TAG, "got URL: '$url'") Intent().also { intent -> intent.action = TRIGGER_PAYMENT_ACTION @@ -187,18 +150,17 @@ class HostCardEmulatorService: HostApduService() { } companion object { - val TAG = "taler-wallet-hce" - val AID = "A0000002471001" - val SELECT_INS = 0xA4 - val PUT_INS = 0xDA - val GET_INS = 0xCA + const val TAG = "taler-wallet-hce" + const val SELECT_INS = 0xA4 + const val PUT_INS = 0xDA + const val GET_INS = 0xCA - val TRIGGER_PAYMENT_ACTION = "net.taler.TRIGGER_PAYMENT_ACTION" + const val TRIGGER_PAYMENT_ACTION = "net.taler.TRIGGER_PAYMENT_ACTION" - val MERCHANT_NFC_CONNECTED = "net.taler.MERCHANT_NFC_CONNECTED" - val MERCHANT_NFC_DISCONNECTED = "net.taler.MERCHANT_NFC_DISCONNECTED" + const val MERCHANT_NFC_CONNECTED = "net.taler.MERCHANT_NFC_CONNECTED" + const val MERCHANT_NFC_DISCONNECTED = "net.taler.MERCHANT_NFC_DISCONNECTED" - val HTTP_TUNNEL_RESPONSE = "net.taler.HTTP_TUNNEL_RESPONSE" - val HTTP_TUNNEL_REQUEST = "net.taler.HTTP_TUNNEL_REQUEST" + const val HTTP_TUNNEL_RESPONSE = "net.taler.HTTP_TUNNEL_RESPONSE" + const val HTTP_TUNNEL_REQUEST = "net.taler.HTTP_TUNNEL_REQUEST" } }
\ No newline at end of file diff --git a/app/src/main/java/net/taler/wallet/MainActivity.kt b/app/src/main/java/net/taler/wallet/MainActivity.kt index fa0b1d9..b3090b8 100644 --- a/app/src/main/java/net/taler/wallet/MainActivity.kt +++ b/app/src/main/java/net/taler/wallet/MainActivity.kt @@ -15,6 +15,7 @@ import androidx.appcompat.widget.Toolbar import androidx.core.view.GravityCompat import androidx.drawerlayout.widget.DrawerLayout import androidx.lifecycle.ViewModelProviders +import androidx.navigation.NavController import androidx.navigation.findNavController import androidx.navigation.ui.AppBarConfiguration import androidx.navigation.ui.setupWithNavController @@ -24,6 +25,7 @@ import com.google.android.material.snackbar.Snackbar import com.google.zxing.integration.android.IntentIntegrator import com.google.zxing.integration.android.IntentResult import me.zhanghai.android.materialprogressbar.MaterialProgressBar +import java.util.* class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener { @@ -52,6 +54,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte navView.setNavigationItemSelectedListener(this) val navController = findNavController(R.id.nav_host_fragment) + val appBarConfiguration = AppBarConfiguration(setOf(R.id.showBalance, R.id.settings, R.id.walletHistory), drawerLayout) @@ -70,7 +73,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte registerReceiver(object : BroadcastReceiver() { override fun onReceive(p0: Context?, p1: Intent?) { - if (model.payStatus.value !is PayStatus.None) { + if (navController.currentDestination?.id == R.id.promptPayment) { return } @@ -183,12 +186,12 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte private fun handleTalerUri(url: String, from: String) { when { - url.startsWith("taler://pay") -> { + url.toLowerCase(Locale.ROOT).startsWith("taler://pay/") -> { Log.v(TAG, "navigating!") findNavController(R.id.nav_host_fragment).navigate(R.id.action_showBalance_to_promptPayment) model.preparePay(url) } - url.startsWith("taler://withdraw") -> { + url.toLowerCase(Locale.ROOT).startsWith("taler://withdraw/") -> { Log.v(TAG, "navigating!") findNavController(R.id.nav_host_fragment).navigate(R.id.action_showBalance_to_promptWithdraw) model.getWithdrawalInfo(url) diff --git a/app/src/main/java/net/taler/wallet/PromptPayment.kt b/app/src/main/java/net/taler/wallet/PromptPayment.kt index 1d828e3..e9652be 100644 --- a/app/src/main/java/net/taler/wallet/PromptPayment.kt +++ b/app/src/main/java/net/taler/wallet/PromptPayment.kt @@ -16,12 +16,6 @@ import androidx.navigation.findNavController import com.google.android.material.snackbar.Snackbar import me.zhanghai.android.materialprogressbar.MaterialProgressBar - -// TODO: Rename parameter arguments, choose names that match -// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER -private const val ARG_PARAM1 = "param1" -private const val ARG_PARAM2 = "param2" - /** * A simple [Fragment] subclass. * @@ -59,7 +53,7 @@ class PromptPayment : Fragment() { triggerLoading() } - fun fillOrderInfo(view: View, contractTerms: ContractTerms, totalFees: Amount?) { + private fun fillOrderInfo(view: View, contractTerms: ContractTerms, totalFees: Amount?) { val feesAmountView = view.findViewById<TextView>(R.id.order_fees_amount) val amountView = view.findViewById<TextView>(R.id.order_amount) val summaryView = view.findViewById<TextView>(R.id.order_summary) @@ -78,7 +72,8 @@ class PromptPayment : Fragment() { } - fun showPayStatus(view: View, payStatus: PayStatus) { + + private fun showPayStatus(view: View, payStatus: PayStatus) { val promptPaymentDetails = view.findViewById<View>(R.id.prompt_payment_details) val balanceInsufficientWarning = view.findViewById<View>(R.id.balance_insufficient_warning) val confirmPaymentButton = view.findViewById<Button>(R.id.button_confirm_payment) @@ -138,7 +133,8 @@ class PromptPayment : Fragment() { val abortPaymentButton = view.findViewById<Button>(R.id.button_abort_payment) abortPaymentButton.setOnClickListener { - activity!!.findNavController(R.id.nav_host_fragment).navigateUp() + model.payStatus.value = PayStatus.None() + requireActivity().findNavController(R.id.nav_host_fragment).navigateUp() } triggerLoading() diff --git a/app/src/main/java/net/taler/wallet/ShowBalance.kt b/app/src/main/java/net/taler/wallet/ShowBalance.kt index ce07816..81de260 100644 --- a/app/src/main/java/net/taler/wallet/ShowBalance.kt +++ b/app/src/main/java/net/taler/wallet/ShowBalance.kt @@ -75,6 +75,8 @@ class PendingOperationsAdapter(private var myDataset: PendingOperations) : Recyc override fun onBindViewHolder(holder: MyViewHolder, position: Int) { val p = myDataset.pending[position] val textView = holder.rowView.findViewById<TextView>(R.id.pending_text) + val subTextView = holder.rowView.findViewById<TextView>(R.id.pending_subtext) + subTextView.text = p.detail.toString(1) textView.text = p.type } diff --git a/app/src/main/java/net/taler/wallet/WalletHistory.kt b/app/src/main/java/net/taler/wallet/WalletHistory.kt index 6c22ad1..d5cd3b6 100644 --- a/app/src/main/java/net/taler/wallet/WalletHistory.kt +++ b/app/src/main/java/net/taler/wallet/WalletHistory.kt @@ -26,8 +26,11 @@ class WalletHistoryAdapter(private var myDataset: HistoryResult) : RecyclerView. } override fun onBindViewHolder(holder: MyViewHolder, position: Int) { + val h = myDataset.history[position] val text = holder.rowView.findViewById<TextView>(R.id.history_text) - text.text = myDataset.history[position].type + val subText = holder.rowView.findViewById<TextView>(R.id.history_subtext) + text.text = h.type + subText.text = h.timestamp.toString() + "\n" + h.detail.toString(1) } fun update(updatedHistory: HistoryResult) { diff --git a/app/src/main/java/net/taler/wallet/WalletViewModel.kt b/app/src/main/java/net/taler/wallet/WalletViewModel.kt index dffc4a0..f8acc2d 100644 --- a/app/src/main/java/net/taler/wallet/WalletViewModel.kt +++ b/app/src/main/java/net/taler/wallet/WalletViewModel.kt @@ -7,7 +7,7 @@ import androidx.lifecycle.MutableLiveData import net.taler.wallet.backend.WalletBackendApi import org.json.JSONObject -val TAG = "taler-wallet" +const val TAG = "taler-wallet" data class Amount(val currency: String, val amount: String) { @@ -77,7 +77,8 @@ open class HistoryResult( open class HistoryEntry( val detail: JSONObject, - val type: String + val type: String, + val timestamp: JSONObject ) open class PendingOperationInfo( @@ -113,6 +114,11 @@ class WalletViewModel(val app: Application) : AndroidViewModel(app) { value = PendingOperations(listOf()) } + private var activeGetBalance = 0 + private var activeGetPending = 0 + + private var currentPayRequestId = 0 + private val walletBackendApi = WalletBackendApi(app) fun init() { @@ -131,11 +137,22 @@ class WalletViewModel(val app: Application) : AndroidViewModel(app) { getBalances() getPending() } + walletBackendApi.connectedHandler = { + activeGetBalance = 0 + activeGetPending = 0 + getBalances() + getPending() + } } fun getBalances() { + if (activeGetBalance > 0) { + return + } + activeGetBalance++ walletBackendApi.sendRequest("getBalances", null) { result -> + activeGetBalance-- val balanceList = mutableListOf<BalanceEntry>() val byCurrency = result.getJSONObject("byCurrency") val currencyList = byCurrency.keys().asSequence().toList().sorted() @@ -153,7 +170,12 @@ class WalletViewModel(val app: Application) : AndroidViewModel(app) { } private fun getPending() { + if (activeGetPending > 0) { + return + } + activeGetPending++ walletBackendApi.sendRequest("getPendingOperations", null) { result -> + activeGetPending-- Log.i(TAG, "got getPending result") val pendingList = mutableListOf<PendingOperationInfo>() val pendingJson = result.getJSONArray("pendingOperations") @@ -177,7 +199,8 @@ class WalletViewModel(val app: Application) : AndroidViewModel(app) { val type = h.getString("type") Log.v(TAG, "got history entry type $type") val detail = h.getJSONObject("detail") - historyEntries.add(HistoryEntry(detail, type)) + val timestamp = h.getJSONObject("timestamp") + historyEntries.add(HistoryEntry(detail, type, timestamp)) } cb(HistoryResult(historyEntries)) } @@ -191,14 +214,21 @@ class WalletViewModel(val app: Application) : AndroidViewModel(app) { } } + fun preparePay(url: String) { val args = JSONObject() args.put("url", url) + this.currentPayRequestId += 1 + val myPayRequestId = this.currentPayRequestId this.payStatus.value = PayStatus.Loading() walletBackendApi.sendRequest("preparePay", args) { result -> Log.v(TAG, "got preparePay result") + if (myPayRequestId != this.currentPayRequestId) { + Log.v(TAG, "preparePay result was for old request") + return@sendRequest + } val status = result.getString("status") var contractTerms: ContractTerms? = null var proposalId: String? = null diff --git a/app/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt b/app/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt index 31e0f08..1c5b170 100644 --- a/app/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt +++ b/app/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt @@ -19,10 +19,12 @@ class WalletBackendApi(private val app: Application) { 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?) { @@ -33,6 +35,10 @@ class WalletBackendApi(private val app: Application) { val msg = Message.obtain(null, WalletBackendService.MSG_SUBSCRIBE_NOTIFY) msg.replyTo = incomingMessenger bm.send(msg) + val ch = connectedHandler + if (ch != null) { + ch() + } } } diff --git a/app/src/main/java/net/taler/wallet/backend/WalletBackendService.kt b/app/src/main/java/net/taler/wallet/backend/WalletBackendService.kt index b72ce6b..26420a1 100644 --- a/app/src/main/java/net/taler/wallet/backend/WalletBackendService.kt +++ b/app/src/main/java/net/taler/wallet/backend/WalletBackendService.kt @@ -22,100 +22,6 @@ import kotlin.system.exitProcess private const val TAG = "taler-wallet-backend" -/** - * Module loader to handle module loading requests from the wallet-core running on node/v8. - */ -private class AssetModuleLoader( - private val assetManager: AssetManager, - private val rootPath: String = "node_modules" -) : AkonoJni.LoadModuleHandler { - - private fun makeResult(localPath: String, stream: InputStream): ModuleResult { - val moduleString = stream.bufferedReader().use { - it.readText() - } - return ModuleResult("/vmodroot/$localPath", moduleString) - } - - private fun tryPath(rawAssetPath: String): ModuleResult? { - //val assetPath = Paths.get(rawAssetPath).normalize().toString() - val assetPath = File(rawAssetPath).normalize().path - try { - val moduleStream = assetManager.open(assetPath) - return makeResult(assetPath, moduleStream) - } catch (e: Exception) { - } - try { - val jsPath = "$assetPath.js" - val moduleStream = assetManager.open(jsPath) - return makeResult(jsPath, moduleStream) - } catch (e: Exception) { - // ignore - } - val packageJsonPath = "$assetPath/package.json" - try { - val packageStream = assetManager.open(packageJsonPath) - val packageString = packageStream.bufferedReader().use { - it.readText() - } - val packageJson = JSONObject(packageString) - val mainFile = try { - packageJson.getString("main") - } catch (e: Exception) { - Log.w(TAG, "package.json does not have a 'main' filed") - throw e - } - try { - //val modPath = Paths.get("$assetPath/$mainFile").normalize().toString() - val modPath = File("$assetPath/$mainFile").normalize().path - return makeResult(modPath, assetManager.open(modPath)) - } catch (e: Exception) { - // ignore - } - try { - //val modPath = Paths.get("$assetPath/$mainFile.js").normalize().toString() - val modPath = File("$assetPath/$mainFile.js").normalize().path - return makeResult(modPath, assetManager.open(modPath)) - } catch (e: Exception) { - } - } catch (e: Exception) { - } - try { - val jsPath = "$assetPath/index.js" - val moduleStream = assetManager.open(jsPath) - return makeResult(jsPath, moduleStream) - } catch (e: Exception) { - } - return null - } - - override fun loadModule(name: String, paths: Array<String>): ModuleResult? { - for (path in paths) { - val prefix = "/vmodroot" - if (!path.startsWith(prefix)) { - continue - } - if (path == prefix) { - val res = tryPath("$rootPath/$name") - if (res != null) - return res - } else { - val res = tryPath(path.drop(prefix.length + 1) + "/$name") - if (res != null) - return res - } - } - return null - } -} - - -private class AssetDataHandler(private val assetManager: AssetManager) : AkonoJni.GetDataHandler { - override fun handleGetData(what: String): ByteArray? { - return null - } -} - class RequestData(val clientRequestID: Int, val messenger: Messenger) @@ -138,16 +44,14 @@ class WalletBackendService : Service() { override fun onCreate() { Log.i(TAG, "onCreate in wallet backend service") akono = AkonoJni() - akono.setLoadModuleHandler(AssetModuleLoader(application.assets)) - akono.setGetDataHandler(AssetDataHandler(application.assets)) akono.setMessageHandler(object : AkonoJni.MessageHandler { override fun handleMessage(message: String) { this@WalletBackendService.handleAkonoMessage(message) } }) akono.evalNodeCode("console.log('hello world from taler wallet-android')") - akono.evalNodeCode("require('source-map-support').install();") - akono.evalNodeCode("tw = require('taler-wallet');") + //akono.evalNodeCode("require('source-map-support').install();") + akono.evalNodeCode("tw = require('taler-wallet-android');") akono.evalNodeCode("tw.installAndroidWalletListener();") sendInitMessage() initialized = true @@ -159,7 +63,7 @@ class WalletBackendService : Service() { msg.put("operation", "init") val args = JSONObject() msg.put("args", args) - args.put("persistentStoragePath", "${application.filesDir}/talerwalletdb.json") + args.put("persistentStoragePath", "${application.filesDir}/talerwalletdb-v27.json") akono.sendMessage(msg.toString()) } diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index a3aa93f..73179cb 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -36,7 +36,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" - android:text="0.6.0pre4 (Tue 03 Dec 2019)" /> + android:text="0.6.0pre4 (Fri 6 Dec 2019)" /> </LinearLayout> @@ -59,7 +59,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" - android:text="0.6.0pre4 (Tue 3 Dec 2019, 829acdd3d9)" /> + android:text="0.6.0pre4 (Fri 6 Dec 2019)" /> </LinearLayout> diff --git a/app/src/main/res/layout/history_row.xml b/app/src/main/res/layout/history_row.xml index 864baa1..669fbd1 100644 --- a/app/src/main/res/layout/history_row.xml +++ b/app/src/main/res/layout/history_row.xml @@ -12,4 +12,11 @@ android:textSize="24sp" tools:text="My History Event"> </TextView> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:id="@+id/history_subtext" + android:textSize="14sp" tools:text="My History Event"> + </TextView> + </LinearLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/pending_row.xml b/app/src/main/res/layout/pending_row.xml index 088ec99..ec5aa2c 100644 --- a/app/src/main/res/layout/pending_row.xml +++ b/app/src/main/res/layout/pending_row.xml @@ -12,4 +12,11 @@ android:textSize="24sp" tools:text="My Pending Operation"> </TextView> + <TextView + android:id="@+id/pending_subtext" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="14sp" + tools:text="My further details" /> + </LinearLayout>
\ No newline at end of file diff --git a/app/src/main/res/xml/apduservice.xml b/app/src/main/res/xml/apduservice.xml index 6d4956b..ac2aa32 100644 --- a/app/src/main/res/xml/apduservice.xml +++ b/app/src/main/res/xml/apduservice.xml @@ -4,6 +4,6 @@ android:requireDeviceUnlock="false"> <aid-group android:description="@string/aiddescription" android:category="other"> - <aid-filter android:name="F00054414c4552"/> + <aid-filter android:name="F00054414C4552"/> </aid-group> </host-apdu-service>
\ No newline at end of file diff --git a/build.gradle b/build.gradle index b8692a6..dfab280 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.5.2' + classpath 'com.android.tools.build:gradle:3.5.3' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files |