gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [taler-wallet-android] branch master updated (884fa0b -> b9


From: gnunet
Subject: [GNUnet-SVN] [taler-wallet-android] branch master updated (884fa0b -> b9fd051)
Date: Thu, 22 Aug 2019 23:37:29 +0200

This is an automated email from the git hooks/post-receive script.

dold pushed a change to branch master
in repository wallet-android.

    from 884fa0b  import into repo
     new defff18  gradle version
     new b9fd051  UX improvements / prototype support for NFC tunneling

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .idea/codeStyles/Project.xml                       | 109 +++++++++++
 app/src/main/AndroidManifest.xml                   |  23 ++-
 .../{PaymentSuccessful.kt => AlreadyPaid.kt}       |  11 +-
 .../net/taler/wallet/HostCardEmulatorService.kt    | 204 +++++++++++++++++++++
 app/src/main/java/net/taler/wallet/MainActivity.kt |  50 ++++-
 .../main/java/net/taler/wallet/PromptPayment.kt    |  27 ++-
 .../main/java/net/taler/wallet/WalletViewModel.kt  |  39 ++++
 ...nt_successful.xml => fragment_already_paid.xml} |  16 +-
 app/src/main/res/navigation/nav_graph.xml          |   9 +
 app/src/main/res/values/strings.xml                |   2 +
 app/src/main/res/xml/apduservice.xml               |   9 +
 build.gradle                                       |   2 +-
 gradle/wrapper/gradle-wrapper.properties           |   2 +-
 13 files changed, 472 insertions(+), 31 deletions(-)
 copy app/src/main/java/net/taler/wallet/{PaymentSuccessful.kt => 
AlreadyPaid.kt} (66%)
 create mode 100644 
app/src/main/java/net/taler/wallet/HostCardEmulatorService.kt
 copy app/src/main/res/layout/{fragment_payment_successful.xml => 
fragment_already_paid.xml} (71%)
 create mode 100644 app/src/main/res/xml/apduservice.xml

diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 1bec35e..ce889bd 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -3,6 +3,115 @@
     <JetCodeStyleSettings>
       <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
     </JetCodeStyleSettings>
+    <codeStyleSettings language="XML">
+      <arrangement>
+        <rules>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>xmlns:android</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>xmlns:.*</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+              <order>BY_NAME</order>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*:id</NAME>
+                  <XML_ATTRIBUTE />
+                  
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*:name</NAME>
+                  <XML_ATTRIBUTE />
+                  
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>name</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>style</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+              <order>BY_NAME</order>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*</NAME>
+                  <XML_ATTRIBUTE />
+                  
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                </AND>
+              </match>
+              <order>ANDROID_ATTRIBUTE_ORDER</order>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>.*</XML_NAMESPACE>
+                </AND>
+              </match>
+              <order>BY_NAME</order>
+            </rule>
+          </section>
+        </rules>
+      </arrangement>
+    </codeStyleSettings>
     <codeStyleSettings language="kotlin">
       <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
     </codeStyleSettings>
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index b675499..3a853c3 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,6 +1,11 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android";
-          package="net.taler.wallet">
+        xmlns:tools="http://schemas.android.com/tools";
+        package="net.taler.wallet">
+
+    <uses-permission android:name="android.permission.NFC" />
+    <uses-feature android:name="android.hardware.nfc.hce"
+            android:required="false" />
 
     <application
             android:allowBackup="true"
@@ -8,7 +13,8 @@
             android:label="@string/app_name"
             android:roundIcon="@mipmap/ic_launcher_round"
             android:supportsRtl="true"
-            android:theme="@style/AppTheme">
+            android:theme="@style/AppTheme"
+            tools:ignore="GoogleAppIndexingWarning">
         <activity
                 android:name=".MainActivity"
                 android:label="@string/app_name"
@@ -19,6 +25,19 @@
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
+
+        <service
+                android:name=".HostCardEmulatorService"
+                android:exported="true"
+                android:permission="android.permission.BIND_NFC_SERVICE">
+            <intent-filter>
+                <action 
android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE" />
+            </intent-filter>
+
+            <meta-data
+                    android:name="android.nfc.cardemulation.host_apdu_service"
+                    android:resource="@xml/apduservice" />
+        </service>
     </application>
 
 </manifest>
\ No newline at end of file
diff --git a/app/src/main/java/net/taler/wallet/PaymentSuccessful.kt 
b/app/src/main/java/net/taler/wallet/AlreadyPaid.kt
similarity index 66%
copy from app/src/main/java/net/taler/wallet/PaymentSuccessful.kt
copy to app/src/main/java/net/taler/wallet/AlreadyPaid.kt
index 039fa73..40903f9 100644
--- a/app/src/main/java/net/taler/wallet/PaymentSuccessful.kt
+++ b/app/src/main/java/net/taler/wallet/AlreadyPaid.kt
@@ -9,24 +9,17 @@ import android.view.ViewGroup
 import android.widget.Button
 import androidx.navigation.findNavController
 
-
-// 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.
- *
  */
-class PaymentSuccessful : Fragment() {
+class AlreadyPaid : Fragment() {
 
     override fun onCreateView(
         inflater: LayoutInflater, container: ViewGroup?,
         savedInstanceState: Bundle?
     ): View? {
         // Inflate the layout for this fragment
-        val view = inflater.inflate(R.layout.fragment_payment_successful, 
container, false)
+        val view = inflater.inflate(R.layout.fragment_already_paid, container, 
false)
         view.findViewById<Button>(R.id.button_success_back).setOnClickListener 
{
             activity!!.findNavController(R.id.nav_host_fragment).navigateUp()
         }
diff --git a/app/src/main/java/net/taler/wallet/HostCardEmulatorService.kt 
b/app/src/main/java/net/taler/wallet/HostCardEmulatorService.kt
new file mode 100644
index 0000000..cdcf492
--- /dev/null
+++ b/app/src/main/java/net/taler/wallet/HostCardEmulatorService.kt
@@ -0,0 +1,204 @@
+package net.taler.wallet
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+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()
+    stream.write(payload)
+    stream.write(0x90)
+    stream.write(0x00)
+    return stream.toByteArray()
+}
+
+
+fun makeApduFailureResponse(): ByteArray {
+    val stream = ByteArrayOutputStream()
+    stream.write(0x6F)
+    stream.write(0x00)
+    return stream.toByteArray()
+}
+
+
+fun readApduBodySize(stream: ByteArrayInputStream): Int {
+    val b0 = stream.read()
+    if (b0 == -1) {
+        return 0;
+    }
+    if (b0 != 0) {
+        return b0
+    }
+    val b1 = stream.read()
+    val b2 = stream.read()
+
+    return (b1 shl 8) and b2
+}
+
+
+class HostCardEmulatorService: HostApduService() {
+
+    val queuedRequests: ConcurrentLinkedDeque<String> = ConcurrentLinkedDeque()
+
+    override fun onCreate() {
+        IntentFilter(HTTP_TUNNEL_REQUEST).also { filter ->
+            registerReceiver(object : BroadcastReceiver() {
+                override fun onReceive(p0: Context?, p1: Intent?) {
+                    
queuedRequests.addLast(p1!!.getStringExtra("tunnelMessage"))
+                }
+            }, filter)
+        }
+    }
+
+    override fun onDeactivated(reason: Int) {
+        Log.d(TAG, "Deactivated: " + reason)
+        Intent().also { intent ->
+            intent.action = MERCHANT_NFC_DISCONNECTED
+            sendBroadcast(intent)
+        }
+    }
+
+    override fun processCommandApdu(commandApdu: ByteArray?,
+                                    extras: Bundle?): ByteArray {
+
+        //Log.d(TAG, "Processing command APDU")
+
+        if (commandApdu == null) {
+            Log.d(TAG, "APDU is null")
+            return makeApduFailureResponse()
+        }
+
+        val stream = ByteArrayInputStream(commandApdu)
+
+        val command = stream.read()
+
+        if (command != 0) {
+            Log.d(TAG, "APDU has invalid command")
+            return makeApduFailureResponse()
+        }
+
+        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")
+
+        if (instruction == SELECT_INS) {
+            // FIXME: validate body!
+            return makeApduSuccessResponse(ByteArray(0))
+        }
+
+        if (instruction == GET_INS) {
+            val req = queuedRequests.poll()
+            return if (req != null) {
+                Log.v(TAG,"sending tunnel request")
+                makeApduSuccessResponse(req.toByteArray(Charsets.UTF_8))
+            } else {
+                makeApduSuccessResponse(ByteArray(0))
+            }
+        }
+
+        if (instruction == PUT_INS) {
+            val bodySize = readApduBodySize(stream)
+
+
+            val talerInstr = stream.read()
+            val bodyBytes = stream.readBytes()
+
+
+            when (talerInstr.toInt()) {
+                1 -> {
+                    val url = String(bodyBytes, Charsets.UTF_8)
+
+                    Intent().also { intent ->
+                        intent.action = TRIGGER_PAYMENT_ACTION
+                        intent.putExtra("contractUrl", url)
+                        sendBroadcast(intent)
+                    }
+                }
+                2 -> {
+                    Log.v(TAG, "got http response: 
${bodyBytes.toString(Charsets.UTF_8)}")
+
+                    Intent().also { intent ->
+                        intent.action = HTTP_TUNNEL_RESPONSE
+                        intent.putExtra("response", 
bodyBytes.toString(Charsets.UTF_8))
+                        sendBroadcast(intent)
+                    }
+                }
+                else -> {
+                    Log.v(TAG, "taler instruction $talerInstr unknown")
+                }
+            }
+
+            return makeApduSuccessResponse(ByteArray(0))
+        }
+
+        return makeApduFailureResponse()
+    }
+
+    companion object {
+        val TAG = "taler-wallet-hce"
+        val AID = "A0000002471001"
+        val SELECT_INS = 0xA4
+        val PUT_INS = 0xDA
+        val GET_INS = 0xCA
+
+        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"
+
+        val HTTP_TUNNEL_RESPONSE = "net.taler.HTTP_TUNNEL_RESPONSE"
+        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 e539cfd..44cd8a6 100644
--- a/app/src/main/java/net/taler/wallet/MainActivity.kt
+++ b/app/src/main/java/net/taler/wallet/MainActivity.kt
@@ -1,7 +1,10 @@
 package net.taler.wallet
 
 
+import android.content.BroadcastReceiver
+import android.content.Context
 import android.content.Intent
+import android.content.IntentFilter
 import android.os.Bundle
 import android.util.Log
 import android.view.Menu
@@ -11,7 +14,6 @@ import androidx.appcompat.app.AppCompatActivity
 import androidx.appcompat.widget.Toolbar
 import androidx.core.view.GravityCompat
 import androidx.drawerlayout.widget.DrawerLayout
-import androidx.lifecycle.Observer
 import androidx.lifecycle.ViewModelProviders
 import androidx.navigation.findNavController
 import androidx.navigation.ui.AppBarConfiguration
@@ -22,6 +24,8 @@ import com.google.zxing.integration.android.IntentIntegrator
 import com.google.zxing.integration.android.IntentResult
 import me.zhanghai.android.materialprogressbar.MaterialProgressBar
 
+
+
 class MainActivity : AppCompatActivity(), 
NavigationView.OnNavigationItemSelectedListener {
 
     lateinit var model: WalletViewModel
@@ -54,6 +58,50 @@ class MainActivity : AppCompatActivity(), 
NavigationView.OnNavigationItemSelecte
 
         model.init()
         model.getBalances()
+
+        val triggerPaymentFilter = 
IntentFilter(HostCardEmulatorService.TRIGGER_PAYMENT_ACTION)
+        registerReceiver(object : BroadcastReceiver() {
+            override fun onReceive(p0: Context?, p1: Intent?) {
+
+                if (model.payStatus.value !is PayStatus.None) {
+                    return
+                }
+
+                val url = p1!!.extras!!.get("contractUrl") as String
+
+                
findNavController(R.id.nav_host_fragment).navigate(R.id.action_showBalance_to_promptPayment)
+                model.preparePay(url)
+
+            }
+        }, triggerPaymentFilter)
+
+        val nfcConnectedFilter = 
IntentFilter(HostCardEmulatorService.MERCHANT_NFC_CONNECTED)
+        registerReceiver(object : BroadcastReceiver() {
+            override fun onReceive(p0: Context?, p1: Intent?) {
+                Log.v(TAG, "got MERCHANT_NFC_CONNECTED")
+                //model.startTunnel()
+            }
+        }, nfcConnectedFilter)
+
+        val nfcDisconnectedFilter = 
IntentFilter(HostCardEmulatorService.MERCHANT_NFC_DISCONNECTED)
+        registerReceiver(object : BroadcastReceiver() {
+            override fun onReceive(p0: Context?, p1: Intent?) {
+                Log.v(TAG, "got MERCHANT_NFC_DISCONNECTED")
+                //model.stopTunnel()
+            }
+        }, nfcDisconnectedFilter)
+
+
+        IntentFilter(HostCardEmulatorService.HTTP_TUNNEL_RESPONSE).also { 
filter ->
+            registerReceiver(object : BroadcastReceiver() {
+                override fun onReceive(p0: Context?, p1: Intent?) {
+                    Log.v("taler-tunnel", "got HTTP_TUNNEL_RESPONSE")
+                    model.tunnelResponse(p1!!.getStringExtra("response"))
+                }
+            }, filter)
+        }
+
+        //model.startTunnel()
     }
 
     override fun onBackPressed() {
diff --git a/app/src/main/java/net/taler/wallet/PromptPayment.kt 
b/app/src/main/java/net/taler/wallet/PromptPayment.kt
index 9486814..07d3dd2 100644
--- a/app/src/main/java/net/taler/wallet/PromptPayment.kt
+++ b/app/src/main/java/net/taler/wallet/PromptPayment.kt
@@ -32,7 +32,8 @@ class PromptPayment : Fragment() {
 
     var fragmentView: View? = null
 
-    fun triggerLoading(loading: Boolean) {
+    fun triggerLoading() {
+        val loading = model.payStatus.value == null || (model.payStatus.value 
is PayStatus.Loading)
         val myActivity = activity!!
         val progressBar = 
myActivity.findViewById<MaterialProgressBar>(R.id.progress_bar)
         if (loading) {
@@ -49,13 +50,13 @@ class PromptPayment : Fragment() {
             ViewModelProviders.of(this)[WalletViewModel::class.java]
         } ?: throw Exception("Invalid Activity")
 
-        triggerLoading(true)
+        triggerLoading()
     }
 
     override fun onResume() {
         super.onResume()
         Log.v("taler-wallet", "called onResume on PromptPayment")
-        triggerLoading(model.payStatus.value == null || model.payStatus.value 
is PayStatus.Loading)
+        triggerLoading()
     }
 
     fun fillOrderInfo(view: View, contractTerms: ContractTerms, totalFees: 
Amount?) {
@@ -90,24 +91,31 @@ class PromptPayment : Fragment() {
 
                 confirmPaymentButton.setOnClickListener {
                     model.confirmPay(payStatus.proposalId)
-                    triggerLoading(true)
                     confirmPaymentButton.isEnabled = false
                 }
-                triggerLoading(false)
             }
             is PayStatus.InsufficientBalance -> {
                 fillOrderInfo(view, payStatus.contractTerms, null)
                 promptPaymentDetails.visibility = View.VISIBLE
                 balanceInsufficientWarning.visibility = View.VISIBLE
                 confirmPaymentButton.isEnabled = false
-                triggerLoading(false)
             }
             is PayStatus.Success -> {
-                triggerLoading(false)
+                model.payStatus.value = PayStatus.None()
                 
activity!!.findNavController(R.id.nav_host_fragment).navigate(R.id.action_promptPayment_to_paymentSuccessful)
             }
+            is PayStatus.AlreadyPaid -> {
+                
activity!!.findNavController(R.id.nav_host_fragment).navigate(R.id.action_promptPayment_to_alreadyPaid)
+                model.payStatus.value = PayStatus.None()
+            }
+            is PayStatus.None -> {
+                // No payment active.
+            }
+            is PayStatus.Loading -> {
+                // Wait until loaded ...
+            }
             else -> {
-                val bar = Snackbar.make(view , "Unexpected result", 
Snackbar.LENGTH_SHORT)
+                val bar = Snackbar.make(view , "Bug: Unexpected result", 
Snackbar.LENGTH_SHORT)
                 bar.show()
             }
         }
@@ -133,9 +141,10 @@ class PromptPayment : Fragment() {
             activity!!.findNavController(R.id.nav_host_fragment).navigateUp()
         }
 
-        triggerLoading(true)
+        triggerLoading()
 
         model.payStatus.observe(this, Observer {
+            triggerLoading()
             showPayStatus(view, it)
         })
         return view
diff --git a/app/src/main/java/net/taler/wallet/WalletViewModel.kt 
b/app/src/main/java/net/taler/wallet/WalletViewModel.kt
index 7c82f81..f644c8d 100644
--- a/app/src/main/java/net/taler/wallet/WalletViewModel.kt
+++ b/app/src/main/java/net/taler/wallet/WalletViewModel.kt
@@ -3,6 +3,7 @@ package net.taler.wallet
 import akono.AkonoJni
 import akono.ModuleResult
 import android.app.Application
+import android.content.Intent
 import android.content.res.AssetManager
 import android.util.Log
 import androidx.lifecycle.AndroidViewModel
@@ -139,6 +140,7 @@ data class WalletBalances(val initialized: Boolean, val 
byCurrency: List<Amount>
 data class ContractTerms(val summary: String, val amount: Amount)
 
 open class PayStatus {
+    class None : PayStatus()
     class Loading : PayStatus()
     data class Prepared(val contractTerms: ContractTerms, val proposalId: Int, 
val totalFees: Amount) : PayStatus()
     data class InsufficientBalance(val contractTerms: ContractTerms) : 
PayStatus()
@@ -165,6 +167,7 @@ class WalletViewModel(val app: Application) : 
AndroidViewModel(app) {
     init {
         isBalanceLoading.value = false
         balances.value = WalletBalances(false, listOf())
+        payStatus.value = PayStatus.None()
     }
 
     fun init() {
@@ -185,6 +188,14 @@ class WalletViewModel(val app: Application) : 
AndroidViewModel(app) {
                     "notification" -> {
                         getBalances()
                     }
+                    "tunnelHttp" -> {
+                        Log.v(TAG, "got http tunnel request!")
+                        Intent().also { intent ->
+                            intent.action = 
HostCardEmulatorService.HTTP_TUNNEL_REQUEST
+                            intent.putExtra("tunnelMessage", messageStr)
+                            app.sendBroadcast(intent)
+                        }
+                    }
                     "response" -> {
                         val operation = message.getString("operation")
                         Log.v(TAG, "got response for operation $operation")
@@ -251,6 +262,7 @@ class WalletViewModel(val app: Application) : 
AndroidViewModel(app) {
 
         sendInitMessage()
 
+
         this.initialized = true
     }
 
@@ -301,6 +313,8 @@ class WalletViewModel(val app: Application) : 
AndroidViewModel(app) {
         msg.put("args", args)
         args.put("url", url)
 
+        this.payStatus.value = PayStatus.Loading()
+
         myAkono.sendMessage(msg.toString())
     }
 
@@ -328,4 +342,29 @@ class WalletViewModel(val app: Application) : 
AndroidViewModel(app) {
 
         getBalances()
     }
+
+    fun startTunnel() {
+        val msg = JSONObject()
+        msg.put("operation", "startTunnel")
+
+        myAkono.sendMessage(msg.toString())
+    }
+
+    fun stopTunnel() {
+        val msg = JSONObject()
+        msg.put("operation", "stopTunnel")
+
+        myAkono.sendMessage(msg.toString())
+    }
+
+    fun tunnelResponse(resp: String) {
+        val respJson = JSONObject(resp)
+
+        val msg = JSONObject()
+        msg.put("operation", "tunnelResponse")
+        msg.put("args", respJson)
+
+        myAkono.sendMessage(msg.toString())
+
+    }
 }
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_payment_successful.xml 
b/app/src/main/res/layout/fragment_already_paid.xml
similarity index 71%
copy from app/src/main/res/layout/fragment_payment_successful.xml
copy to app/src/main/res/layout/fragment_already_paid.xml
index 64ddad9..69c949e 100644
--- a/app/src/main/res/layout/fragment_payment_successful.xml
+++ b/app/src/main/res/layout/fragment_already_paid.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android";
-             xmlns:tools="http://schemas.android.com/tools";
-             android:layout_width="match_parent"
-             android:layout_height="match_parent"
-             android:layout_margin="15dp"
-             tools:context=".PaymentSuccessful">
+        xmlns:tools="http://schemas.android.com/tools";
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_margin="15dp"
+        tools:context=".PaymentSuccessful">
 
 
     <LinearLayout
@@ -13,20 +13,20 @@
             android:layout_height="match_parent">
 
         <Space android:layout_width="match_parent" android:layout_height="0dp"
-        android:layout_weight="1"/>
+                android:layout_weight="1"/>
 
         <TextView
                 android:layout_gravity="center"
                 android:layout_width="match_parent"
                 android:textAlignment="center"
                 android:layout_height="50dp"
-                android:text="Payment was Successful"
+                android:text="You've already paid for this order."
                 android:autoSizeTextType="uniform"
                 android:textColor="@android:color/holo_green_dark"/>
 
 
         <Space android:layout_width="match_parent" android:layout_height="0dp"
-               android:layout_weight="1"/>
+                android:layout_weight="1"/>
         <Button
                 android:text="Go Back"
                 android:layout_width="match_parent"
diff --git a/app/src/main/res/navigation/nav_graph.xml 
b/app/src/main/res/navigation/nav_graph.xml
index 174c907..80a94ec 100644
--- a/app/src/main/res/navigation/nav_graph.xml
+++ b/app/src/main/res/navigation/nav_graph.xml
@@ -12,6 +12,10 @@
               android:label="Review Payment" 
tools:layout="@layout/fragment_prompt_payment">
         <action android:id="@+id/action_promptPayment_to_paymentSuccessful" 
app:destination="@id/paymentSuccessful"
                 app:popUpTo="@id/showBalance"/>
+        <action
+                android:id="@+id/action_promptPayment_to_alreadyPaid"
+                app:destination="@id/alreadyPaid"
+                app:popUpTo="@id/showBalance"/>
     </fragment>
     <fragment android:id="@+id/paymentSuccessful" 
android:name="net.taler.wallet.PaymentSuccessful"
               android:label="Payment Successful" 
tools:layout="@layout/fragment_payment_successful"/>
@@ -19,4 +23,9 @@
               tools:layout="@layout/fragment_settings"/>
     <fragment android:id="@+id/walletHistory" 
android:name="net.taler.wallet.WalletHistory"
               android:label="History" 
tools:layout="@layout/fragment_show_history"/>
+    <fragment
+            android:id="@+id/alreadyPaid"
+            android:name="net.taler.wallet.AlreadyPaid"
+            android:label="Already Paid"
+            tools:layout="@layout/fragment_already_paid" />
 </navigation>
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml 
b/app/src/main/res/values/strings.xml
index f059311..658dc62 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -16,4 +16,6 @@
 
     <!-- TODO: Remove or change this placeholder text -->
     <string name="hello_blank_fragment">Hello blank fragment</string>
+    <string name="servicedesc">my service</string>
+    <string name="aiddescription">my aid</string>
 </resources>
diff --git a/app/src/main/res/xml/apduservice.xml 
b/app/src/main/res/xml/apduservice.xml
new file mode 100644
index 0000000..b862ccb
--- /dev/null
+++ b/app/src/main/res/xml/apduservice.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android";
+        android:description="@string/servicedesc"
+        android:requireDeviceUnlock="false">
+    <aid-group android:description="@string/aiddescription"
+            android:category="other">
+        <aid-filter android:name="A0000002471001"/>
+    </aid-group>
+</host-apdu-service>
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 438d280..4420c59 100644
--- a/build.gradle
+++ b/build.gradle
@@ -8,7 +8,7 @@ buildscript {
         
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:3.4.2'
+        classpath 'com.android.tools.build:gradle:3.5.0'
         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
diff --git a/gradle/wrapper/gradle-wrapper.properties 
b/gradle/wrapper/gradle-wrapper.properties
index 9664d9d..15c2d72 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip

-- 
To stop receiving notification emails like this one, please contact
address@hidden.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]