diff --git a/.gitignore b/.gitignore index 9e7e35b..add4a36 100644 --- a/.gitignore +++ b/.gitignore @@ -84,3 +84,13 @@ local.properties /virtualsmartcard/lib /virtualsmartcard/win32/BixVReader/Release /virtualsmartcard/win32/Release + +ACardEmulator/build +build/ +crash-info/ +.sign/ +.sdk_delta.info +.rds_delta + +*.apk +keystore.properties \ No newline at end of file diff --git a/ACardEmulator/app/.gitignore b/ACardEmulator/app/.gitignore index 796b96d..42afabf 100644 --- a/ACardEmulator/app/.gitignore +++ b/ACardEmulator/app/.gitignore @@ -1 +1 @@ -/build +/build \ No newline at end of file diff --git a/ACardEmulator/app/app.iml b/ACardEmulator/app/app.iml index 37d5d64..1c17e52 100644 --- a/ACardEmulator/app/app.iml +++ b/ACardEmulator/app/app.iml @@ -32,12 +32,14 @@ + + @@ -87,12 +89,8 @@ - - - - @@ -101,39 +99,32 @@ - - - - - - - - - - - - - - - - + + + + + + + + + \ No newline at end of file diff --git a/ACardEmulator/app/build.gradle b/ACardEmulator/app/build.gradle index a1eb2b5..6f5295e 100644 --- a/ACardEmulator/app/build.gradle +++ b/ACardEmulator/app/build.gradle @@ -3,7 +3,6 @@ apply plugin: 'com.android.application' android { compileSdkVersion 23 buildToolsVersion "23.0.1" - defaultConfig { applicationId "com.vsmartcard.acardemulator" minSdkVersion 19 @@ -49,12 +48,12 @@ android.applicationVariants.all { variant -> } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) + compile fileTree(include: ['*.jar'], dir: 'libs') compile 'com.android.support:appcompat-v7:23.0.1' compile 'com.android.support:support-v4:23.0.1' compile 'com.android.support:design:23.2.1' - compile 'com.journeyapps:zxing-android-embedded:3.2.0@aar' compile 'com.google.zxing:core:3.2.1' - compile group: 'com.madgag.spongycastle', name: 'core', version: '1.51.0.0' + compile 'com.madgag.spongycastle:core:1.51.0.0' + compile files('libs/sdk-v1.0.0.jar') } diff --git a/ACardEmulator/app/libs/accessory-v2.3.2.jar b/ACardEmulator/app/libs/accessory-v2.3.2.jar new file mode 100644 index 0000000..107a3f5 Binary files /dev/null and b/ACardEmulator/app/libs/accessory-v2.3.2.jar differ diff --git a/ACardEmulator/app/libs/sdk-v1.0.0.jar b/ACardEmulator/app/libs/sdk-v1.0.0.jar new file mode 100644 index 0000000..070d65d Binary files /dev/null and b/ACardEmulator/app/libs/sdk-v1.0.0.jar differ diff --git a/ACardEmulator/app/src/main/AndroidManifest.xml b/ACardEmulator/app/src/main/AndroidManifest.xml index a78ad84..9cd3a62 100644 --- a/ACardEmulator/app/src/main/AndroidManifest.xml +++ b/ACardEmulator/app/src/main/AndroidManifest.xml @@ -6,6 +6,13 @@ + + + + + + + - @@ -47,6 +54,24 @@ + + + + + + + + + + + + + + diff --git a/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/EmulatorHostApduService.java b/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/EmulatorHostApduService.java new file mode 100644 index 0000000..a0fe639 --- /dev/null +++ b/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/EmulatorHostApduService.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015 Frank Morgner + * + * This file is part of ACardEmulator. + * + * ACardEmulator 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 of the License, or (at your + * option) any later version. + * + * ACardEmulator 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 + * ACardEmulator. If not, see . + */ + +package com.vsmartcard.acardemulator; + +import android.content.Intent; +import android.nfc.cardemulation.HostApduService; +import android.os.Bundle; +import android.support.v4.content.LocalBroadcastManager; +import android.util.Log; + +import com.vsmartcard.acardemulator.emulators.EmulatorSingleton; + +public class EmulatorHostApduService extends HostApduService { + + @Override + public void onCreate() { + super.onCreate(); + EmulatorSingleton.createEmulator(this); + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + @Override + public byte[] processCommandApdu(byte[] capdu, Bundle extras) { + return EmulatorSingleton.process(this, capdu); + } + + @Override + public void onDeactivated(int reason) { + Intent i = new Intent(EmulatorSingleton.TAG); + + Log.d("", "End transaction"); + switch (reason) { + case DEACTIVATION_LINK_LOSS: + i.putExtra(EmulatorSingleton.EXTRA_DESELECT, "link lost"); + EmulatorSingleton.deactivate(); + break; + case DEACTIVATION_DESELECTED: + EmulatorSingleton.deactivate(); + break; + } + + LocalBroadcastManager.getInstance(this).sendBroadcast(i); + } +} diff --git a/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/MainActivity.java b/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/MainActivity.java index e151d6e..d88f470 100644 --- a/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/MainActivity.java +++ b/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/MainActivity.java @@ -41,6 +41,8 @@ import android.view.View; import android.widget.TextView; import android.widget.Toast; +import com.vsmartcard.acardemulator.emulators.EmulatorSingleton; + public class MainActivity extends AppCompatActivity { @@ -48,12 +50,12 @@ public class MainActivity extends AppCompatActivity { private BroadcastReceiver bReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(EmulatorService.TAG)) { - String capdu = intent.getStringExtra(EmulatorService.EXTRA_CAPDU); - String rapdu = intent.getStringExtra(EmulatorService.EXTRA_RAPDU); - String error = intent.getStringExtra(EmulatorService.EXTRA_ERROR); - String deselect = intent.getStringExtra(EmulatorService.EXTRA_DESELECT); - String install = intent.getStringExtra(EmulatorService.EXTRA_INSTALL); + if (intent.getAction().equals(EmulatorSingleton.TAG)) { + String capdu = intent.getStringExtra(EmulatorSingleton.EXTRA_CAPDU); + String rapdu = intent.getStringExtra(EmulatorSingleton.EXTRA_RAPDU); + String error = intent.getStringExtra(EmulatorSingleton.EXTRA_ERROR); + String deselect = intent.getStringExtra(EmulatorSingleton.EXTRA_DESELECT); + String install = intent.getStringExtra(EmulatorSingleton.EXTRA_INSTALL); if (install != null) textViewVPCDStatus.append(getResources().getString(R.string.status_install) + ":" + install + "\n"); if (capdu != null) @@ -102,7 +104,7 @@ public class MainActivity extends AppCompatActivity { if (emulator != getString(R.string.vicc)) { Snackbar.make(view, "Scheduled re-installation of all applets...", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); - EmulatorService.destroySimulator(getApplicationContext()); + EmulatorSingleton.destroyEmulator(); } } }); @@ -116,8 +118,11 @@ public class MainActivity extends AppCompatActivity { LocalBroadcastManager bManager = LocalBroadcastManager.getInstance(this); IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(EmulatorService.TAG); + intentFilter.addAction(EmulatorSingleton.TAG); bManager.registerReceiver(bReceiver, intentFilter); + + Intent serviceIntent = new Intent(this.getApplicationContext(), SmartcardProviderService.class); + startService(serviceIntent); } @Override diff --git a/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/SettingsActivity.java b/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/SettingsActivity.java index a108105..f7e7c94 100644 --- a/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/SettingsActivity.java +++ b/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/SettingsActivity.java @@ -200,6 +200,8 @@ public class SettingsActivity extends AppCompatPreferenceActivity { return true; } }); + + bindPreferenceSummaryToValue(findPreference("nfc")); } @Override diff --git a/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/SmartcardProviderService.java b/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/SmartcardProviderService.java new file mode 100644 index 0000000..fa35f93 --- /dev/null +++ b/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/SmartcardProviderService.java @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * Neither the name of Samsung Electronics Co., Ltd. nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.vsmartcard.acardemulator; + +import android.content.Intent; +import android.os.Binder; +import android.os.Handler; +import android.os.IBinder; +import android.text.TextUtils; +import android.util.Log; +import android.widget.Toast; + +import com.samsung.android.sdk.SsdkUnsupportedException; +import com.samsung.android.sdk.accessory.SA; +import com.samsung.android.sdk.accessory.SAAgent; +import com.samsung.android.sdk.accessory.SAAuthenticationToken; +import com.samsung.android.sdk.accessory.SAPeerAgent; +import com.samsung.android.sdk.accessory.SASocket; +import com.vsmartcard.acardemulator.emulators.EmulatorSingleton; + +import java.io.IOException; + +public class SmartcardProviderService extends SAAgent { + private static final String TAG = "ACardEmulator"; + private static final int ACCESSORY_CHANNEL_ID = 104; + private static final Class SASOCKET_CLASS = ServiceConnection.class; + private final IBinder mBinder = new LocalBinder(); + private ServiceConnection mConnectionHandler = null; + Handler mHandler = new Handler(); + + public SmartcardProviderService() { + super(TAG, SASOCKET_CLASS); + } + + @Override + public void onCreate() { + super.onCreate(); + SA mAccessory = new SA(); + try { + mAccessory.initialize(this); + EmulatorSingleton.createEmulator(this); + } catch (SsdkUnsupportedException e) { + // try to handle SsdkUnsupportedException + if (processUnsupportedException(e)) { + EmulatorSingleton.createEmulator(this); + return; + } + } catch (Exception e1) { + e1.printStackTrace(); + /* + * Your application can not use Samsung Accessory SDK. Your application should work smoothly + * without using this SDK, or you may want to notify user and close your application gracefully + * (release resources, stop Service threads, close UI thread, etc.) + */ + stopSelf(); + } + findPeerAgents(); + } + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } + + @Override + protected void onFindPeerAgentsResponse(SAPeerAgent[] peerAgents, int result) { + switch (result) { + case PEER_AGENT_FOUND: + break; + case FINDPEER_SERVICE_NOT_FOUND: + break; + case FINDPEER_DEVICE_NOT_CONNECTED: + break; + default: + break; + } + Log.d(TAG, "onFindPeerAgentResponse : result =" + result); + } + + @Override + protected void onServiceConnectionRequested(SAPeerAgent peerAgent) { + if (peerAgent != null) { + //TODO: Check for keys and everything + acceptServiceConnectionRequest(peerAgent); + } + } + + @Override + protected void onServiceConnectionResponse(SAPeerAgent peerAgent, SASocket socket, int result) { + if (result == SAAgent.CONNECTION_SUCCESS) { + if (socket != null) { + mConnectionHandler = (ServiceConnection) socket; + Toast.makeText(getBaseContext(), "connection established", Toast.LENGTH_SHORT).show(); + } + } else if (result == SAAgent.CONNECTION_ALREADY_EXIST) { + Log.e(TAG, "onServiceConnectionResponse, CONNECTION_ALREADY_EXIST"); + } + } + + @Override + protected void onAuthenticationResponse(SAPeerAgent peerAgent, SAAuthenticationToken authToken, int error) { + /* + * The authenticatePeerAgent(peerAgent) API may not be working properly depending on the firmware + * version of accessory device. Please refer to another sample application for Security. + */ + } + + @Override + protected void onError(SAPeerAgent peerAgent, String errorMessage, int errorCode) { + super.onError(peerAgent, errorMessage, errorCode); + } + + private boolean processUnsupportedException(SsdkUnsupportedException e) { + e.printStackTrace(); + int errType = e.getType(); + if (errType == SsdkUnsupportedException.VENDOR_NOT_SUPPORTED + || errType == SsdkUnsupportedException.DEVICE_NOT_SUPPORTED) { + /* + * Your application can not use Samsung Accessory SDK. You application should work smoothly + * without using this SDK, or you may want to notify user and close your app gracefully (release + * resources, stop Service threads, close UI thread, etc.) + */ + stopSelf(); + } else if (errType == SsdkUnsupportedException.LIBRARY_NOT_INSTALLED) { + Log.e(TAG, "You need to install Samsung Accessory SDK to use this application."); + } else if (errType == SsdkUnsupportedException.LIBRARY_UPDATE_IS_REQUIRED) { + Log.e(TAG, "You need to update Samsung Accessory SDK to use this application."); + } else if (errType == SsdkUnsupportedException.LIBRARY_UPDATE_IS_RECOMMENDED) { + Log.e(TAG, "We recommend that you update your Samsung Accessory SDK before using this application."); + return false; + } + return true; + } + + public class LocalBinder extends Binder { + public SmartcardProviderService getService() { + return SmartcardProviderService.this; + } + } + + public class ServiceConnection extends SASocket { + public ServiceConnection() { + super(ServiceConnection.class.getName()); + } + + @Override + public void onError(int channelId, String errorMessage, int errorCode) { + } + + @Override + public void onReceive(int channelId, byte[] data) { + if (mConnectionHandler == null) { + return; + } + final byte[] sendResponse; + if (data[0] == 'd') { + // APDU is sent + byte[] newData = new byte[data.length - 1]; + System.arraycopy(data, 1, newData, 0, data.length - 1); + byte[] response = EmulatorSingleton.process(getApplicationContext(), newData); + sendResponse = new byte[response.length + 1]; + sendResponse[0] = 'd'; + System.arraycopy(response, 0, sendResponse, 1, response.length); + } else if (data[0] == 'a') { + // request for aids + String[] aidList = EmulatorSingleton.getRegisteredAids(getApplicationContext()); + String aidListJoined = TextUtils.join(",", aidList); + sendResponse = new byte[aidListJoined.length() + 1]; + sendResponse[0] = 'a'; + byte[] aids = aidListJoined.getBytes(); + System.arraycopy(aids, 0, sendResponse, 1, aids.length); + } else { + Log.e(TAG, "unknown message from consumer: " + new String(data)); + return; + } + new Thread(new Runnable() { + public void run() { + try { + mConnectionHandler.send(ACCESSORY_CHANNEL_ID, sendResponse); + } catch (IOException e) { + e.printStackTrace(); + } + } + }).start(); + } + + @Override + protected void onServiceConnectionLost(int reason) { + mConnectionHandler = null; + EmulatorSingleton.deactivate(); + mHandler.post(new Runnable() { + @Override + public void run() { + Toast.makeText(getBaseContext(), "connection lost", Toast.LENGTH_SHORT).show(); + } + }); + } + } +} diff --git a/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/EmulatorService.java b/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/emulators/EmulatorSingleton.java similarity index 58% rename from ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/EmulatorService.java rename to ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/emulators/EmulatorSingleton.java index d462bb0..d0fcdbd 100644 --- a/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/EmulatorService.java +++ b/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/emulators/EmulatorSingleton.java @@ -17,28 +17,31 @@ * ACardEmulator. If not, see . */ -package com.vsmartcard.acardemulator; +package com.vsmartcard.acardemulator.emulators; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; -import android.nfc.cardemulation.HostApduService; -import android.os.Bundle; -import android.os.StrictMode; +import android.content.res.Resources; +import android.content.res.XmlResourceParser; +import android.nfc.NfcAdapter; +import android.nfc.cardemulation.CardEmulation; import android.preference.PreferenceManager; +import android.support.annotation.XmlRes; import android.support.v4.content.LocalBroadcastManager; import android.util.Log; +import com.vsmartcard.acardemulator.R; +import com.vsmartcard.acardemulator.Util; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + import java.io.IOException; -import java.net.InetAddress; -import java.net.Socket; - -import com.vsmartcard.acardemulator.emulators.Emulator; -import com.vsmartcard.acardemulator.emulators.JCEmulator; -import com.vsmartcard.acardemulator.emulators.VICCEmulator; - -public class EmulatorService extends HostApduService { +import java.util.ArrayList; +import java.util.List; +public class EmulatorSingleton { public static final String TAG = "com.vsmartcard.acardemulator.EmulatorService"; public static final String EXTRA_CAPDU = "MSG_CAPDU"; public static final String EXTRA_RAPDU = "MSG_RAPDU"; @@ -49,22 +52,35 @@ public class EmulatorService extends HostApduService { private static Emulator emulator = null; private static boolean do_destroy = false; - @Override - public void onCreate () { - super.onCreate(); + private static void destroyEmulatorIfRequested(Context context) { + if (do_destroy) { + emulator.destroy(); + emulator = null; + do_destroy = false; + Intent i = new Intent(TAG); + i.putExtra(EXTRA_DESELECT, "Uninstalled all applets."); + LocalBroadcastManager.getInstance(context).sendBroadcast(i); + } + } + + public static void destroyEmulator() { + do_destroy = true; + } + + public static void createEmulator(Context context) { // force reloading applets if requested - do_destroy(); + destroyEmulatorIfRequested(context); if (emulator == null) { Log.d("", "Begin transaction"); - SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(this); + SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(context); String str_emulator = SP.getString("emulator", ""); - if (str_emulator.equals(getString(R.string.vicc))) { + if (str_emulator.equals(context.getString(R.string.vicc))) { emulator = new VICCEmulator( SP.getString("hostname", VICCEmulator.DEFAULT_HOSTNAME), Integer.parseInt(SP.getString("port", Integer.toString(VICCEmulator.DEFAULT_PORT)))); } else { - emulator = new JCEmulator(this, + emulator = new JCEmulator(context, SP.getBoolean("activate_helloworld", false), SP.getBoolean("activate_openpgp", false), SP.getBoolean("activate_oath", false), @@ -74,55 +90,45 @@ public class EmulatorService extends HostApduService { } } - public static void destroySimulator(Context context) { - do_destroy = true; - } - - private void do_destroy() { - if (do_destroy) { - emulator.destroy(); - emulator = null; - do_destroy = false; - Intent i = new Intent(TAG); - i.putExtra(EXTRA_DESELECT, "Uninstalled all applets."); - LocalBroadcastManager.getInstance(this).sendBroadcast(i); - } - } - - @Override - public void onDestroy() { - do_destroy(); - super.onDestroy(); - } - - @Override - public byte[] processCommandApdu(byte[] capdu, Bundle extras) { + public static byte[] process(Context context, byte[] capdu) { byte[] rapdu = emulator.process(capdu); Intent i = new Intent(TAG); i.putExtra(EXTRA_CAPDU, Util.byteArrayToHexString(capdu)); if (rapdu != null) i.putExtra(EXTRA_RAPDU, Util.byteArrayToHexString(rapdu)); - LocalBroadcastManager.getInstance(this).sendBroadcast(i); + LocalBroadcastManager.getInstance(context).sendBroadcast(i); return rapdu; } - @Override - public void onDeactivated(int reason) { - Intent i = new Intent(TAG); + public static String[] getRegisteredAids(Context context) { + List aidList = new ArrayList<>(); + XmlResourceParser aidXmlParser = context.getResources().getXml(R.xml.aid_list); - Log.d("", "End transaction"); - switch (reason) { - case DEACTIVATION_LINK_LOSS: - i.putExtra(EXTRA_DESELECT, "link lost"); - emulator.deactivate(); - break; - case DEACTIVATION_DESELECTED: - emulator.deactivate(); - break; + try { + while (aidXmlParser.getEventType() != XmlPullParser.END_DOCUMENT) { + if (aidXmlParser.getEventType() == XmlPullParser.START_TAG) { + if (aidXmlParser.getName().equals("aid-filter")) { + int aid = aidXmlParser.getAttributeResourceValue(0, -1); + if (aid != -1) { + aidList.add(context.getResources().getString(aid)); + } + } + } + + aidXmlParser.next(); + } + + aidXmlParser.close(); + } catch (XmlPullParserException | IOException e) { + Log.e(TAG.substring(0, 23), "Couldn't parse aid xml list."); } - LocalBroadcastManager.getInstance(this).sendBroadcast(i); + return aidList.toArray(new String[0]); } -} + + public static void deactivate() { + emulator.deactivate(); + } +} \ No newline at end of file diff --git a/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/emulators/JCEmulator.java b/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/emulators/JCEmulator.java index 99470d4..1ff6967 100644 --- a/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/emulators/JCEmulator.java +++ b/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/emulators/JCEmulator.java @@ -9,7 +9,6 @@ import com.licel.jcardsim.base.SimulatorRuntime; import com.licel.jcardsim.samples.HelloWorldApplet; import com.licel.jcardsim.utils.AIDUtil; import com.mysmartlogon.gidsApplet.GidsApplet; -import com.vsmartcard.acardemulator.EmulatorService; import com.vsmartcard.acardemulator.R; import com.vsmartcard.acardemulator.Util; @@ -100,11 +99,11 @@ public class JCEmulator implements Emulator { } } - Intent i = new Intent(EmulatorService.TAG); + Intent i = new Intent(EmulatorSingleton.TAG); if (!extra_error.isEmpty()) - i.putExtra(EmulatorService.EXTRA_ERROR, extra_error); + i.putExtra(EmulatorSingleton.EXTRA_ERROR, extra_error); if (!extra_install.isEmpty()) - i.putExtra(EmulatorService.EXTRA_INSTALL, extra_install); + i.putExtra(EmulatorSingleton.EXTRA_INSTALL, extra_install); LocalBroadcastManager.getInstance(context).sendBroadcast(i); } diff --git a/ACardEmulator/app/src/main/res/layout/activity_main.xml b/ACardEmulator/app/src/main/res/layout/activity_main.xml index 8b0042d..cc41a10 100644 --- a/ACardEmulator/app/src/main/res/layout/activity_main.xml +++ b/ACardEmulator/app/src/main/res/layout/activity_main.xml @@ -4,7 +4,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" - tools:context="com.vsmartcard.smartcardemulator.MainActivity"> + tools:context="com.vsmartcard.acardemulator.MainActivity"> Builtin Java Card Simulator Remote Virtual Smart Card + + + @string/nfc + @string/gear + + Builtin NFC + Samsung Accessory + If you choose the virtual smart card (VICC) as emulator, you need to start the it on your computer with the `--reversed` flag and configure the connection parameters here accordingly. VICC Port VICC Hostname diff --git a/ACardEmulator/app/src/main/res/xml/accessoryservices.xml b/ACardEmulator/app/src/main/res/xml/accessoryservices.xml new file mode 100644 index 0000000..1a5c7cf --- /dev/null +++ b/ACardEmulator/app/src/main/res/xml/accessoryservices.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + ]> + + + + + + + + + + + + + \ No newline at end of file diff --git a/ACardEmulator/app/src/main/res/xml/settings.xml b/ACardEmulator/app/src/main/res/xml/settings.xml index ed95cc3..17148a2 100644 --- a/ACardEmulator/app/src/main/res/xml/settings.xml +++ b/ACardEmulator/app/src/main/res/xml/settings.xml @@ -81,4 +81,11 @@ + + \ No newline at end of file diff --git a/ACardEmulator/build.gradle b/ACardEmulator/build.gradle index f6e9073..b193299 100644 --- a/ACardEmulator/build.gradle +++ b/ACardEmulator/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.1.0' + classpath 'com.android.tools.build:gradle:2.2.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/ACardEmulator/gradle/wrapper/gradle-wrapper.properties b/ACardEmulator/gradle/wrapper/gradle-wrapper.properties index 12caca0..e92364a 100644 --- a/ACardEmulator/gradle/wrapper/gradle-wrapper.properties +++ b/ACardEmulator/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu May 12 09:46:58 CEST 2016 +#Tue Oct 04 22:11:09 CEST 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip diff --git a/TCardEmulator/.cproject b/TCardEmulator/.cproject new file mode 100644 index 0000000..b235747 --- /dev/null +++ b/TCardEmulator/.cproject @@ -0,0 +1,460 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TCardEmulator/.exportMap b/TCardEmulator/.exportMap new file mode 100644 index 0000000..43e310e --- /dev/null +++ b/TCardEmulator/.exportMap @@ -0,0 +1,4 @@ +{ + global: main; + local: *; +}; diff --git a/TCardEmulator/.gitignore b/TCardEmulator/.gitignore new file mode 100644 index 0000000..65fa71e --- /dev/null +++ b/TCardEmulator/.gitignore @@ -0,0 +1,2 @@ +/Debug +/SA_Report diff --git a/TCardEmulator/.project b/TCardEmulator/.project new file mode 100644 index 0000000..1b8a612 --- /dev/null +++ b/TCardEmulator/.project @@ -0,0 +1,52 @@ + + + TCardEmulator + + + + + + org.tizen.nativecore.apichecker.apicheckerbuilder + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + org.tizen.nativecore.apichecker.apicheckernature + + + + 1464204018079 + + 26 + + org.eclipse.ui.ide.multiFilter + 1.0-projectRelativePath-matches-false-false-*/.tpk + + + + 1464204018094 + + 6 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-project_def.prop + + + + diff --git a/TCardEmulator/.tproject b/TCardEmulator/.tproject new file mode 100644 index 0000000..8259637 --- /dev/null +++ b/TCardEmulator/.tproject @@ -0,0 +1,12 @@ + + + + + wearable-2.3.1 + + + + + + + diff --git a/TCardEmulator/inc/sap_app.h b/TCardEmulator/inc/sap_app.h new file mode 100644 index 0000000..38e8a75 --- /dev/null +++ b/TCardEmulator/inc/sap_app.h @@ -0,0 +1,11 @@ +#ifndef __sap_H__ +#define __sap_H__ + +#include + +void send_apdu_response(nfc_se_h handle, unsigned char *resp, unsigned int resp_len); +void install_aids(void *buffer, unsigned int buffer_size); + +extern gboolean agent_connected; + +#endif /* __tcardemulator_H__ */ diff --git a/TCardEmulator/inc/tcardemulator.h b/TCardEmulator/inc/tcardemulator.h new file mode 100644 index 0000000..ca74f0d --- /dev/null +++ b/TCardEmulator/inc/tcardemulator.h @@ -0,0 +1,21 @@ +#ifndef __tcardemulator_H__ +#define __tcardemulator_H__ + +#define LOG_TAG "tcardemulator" + +#if !defined(PACKAGE) +#define PACKAGE "com.vsmartcard.tcardemulator" +#endif + +#include +#include +#include +#include + +void initialize_sap(); +gboolean find_peers(); +gboolean request_service_connection(void); +gboolean terminate_service_connection(void); +gboolean send_data(nfc_se_h nfc_handle, char* prefix, unsigned int prefix_len, void *message, unsigned int message_len); + +#endif /* __tcardemulator_H__ */ diff --git a/TCardEmulator/res/accessoryservices.xml b/TCardEmulator/res/accessoryservices.xml new file mode 100644 index 0000000..e2265f1 --- /dev/null +++ b/TCardEmulator/res/accessoryservices.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + diff --git a/TCardEmulator/shared/res/ic_launcher.png b/TCardEmulator/shared/res/ic_launcher.png new file mode 100644 index 0000000..b02b6cf Binary files /dev/null and b/TCardEmulator/shared/res/ic_launcher.png differ diff --git a/TCardEmulator/shared/res/tcardemulator.png b/TCardEmulator/shared/res/tcardemulator.png new file mode 100644 index 0000000..9765b1b Binary files /dev/null and b/TCardEmulator/shared/res/tcardemulator.png differ diff --git a/TCardEmulator/shared/res/wallet.xml b/TCardEmulator/shared/res/wallet.xml new file mode 100644 index 0000000..e895b95 --- /dev/null +++ b/TCardEmulator/shared/res/wallet.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/TCardEmulator/src/sap.c b/TCardEmulator/src/sap.c new file mode 100644 index 0000000..1eb92ca --- /dev/null +++ b/TCardEmulator/src/sap.c @@ -0,0 +1,372 @@ +#include "tcardemulator.h" +#include "sap_app.h" +#include +#include +#include +#include +#include +#include + +#define ACCESSORY_PROFILE_ID "/com/vsmcartcard" +#define ACCESSORY_CHANNELID 104 + +typedef struct priv { + sap_agent_h agent; + sap_socket_h socket; + sap_peer_agent_h peer_agent; + nfc_se_h nfc_handle; +} priv_s; + +gboolean agent_created = FALSE; +gboolean agent_connected = FALSE; + +static priv_s priv_data = { 0 }; + +void on_peer_agent_updated(sap_peer_agent_h peer_agent, + sap_peer_agent_status_e peer_status, + sap_peer_agent_found_result_e result, + void *user_data) { + switch (result) { + case SAP_PEER_AGENT_FOUND_RESULT_DEVICE_NOT_CONNECTED: + dlog_print(DLOG_INFO, LOG_TAG, "device is not connected"); + break; + + case SAP_PEER_AGENT_FOUND_RESULT_FOUND: + if (peer_status == SAP_PEER_AGENT_STATUS_AVAILABLE) { + priv_data.peer_agent = peer_agent; + dlog_print(DLOG_INFO, LOG_TAG, "requesting service connection"); + request_service_connection(); + } else { + dlog_print(DLOG_INFO, LOG_TAG, "peer agent removed"); + sap_peer_agent_destroy(peer_agent); + } + break; + + case SAP_PEER_AGENT_FOUND_RESULT_SERVICE_NOT_FOUND: + dlog_print(DLOG_INFO, LOG_TAG, "service not found"); + break; + + case SAP_PEER_AGENT_FOUND_RESULT_TIMEDOUT: + dlog_print(DLOG_INFO, LOG_TAG, "peer agent find timed out"); + break; + + case SAP_PEER_AGENT_FOUND_RESULT_INTERNAL_ERROR: + dlog_print(DLOG_INFO, LOG_TAG, "peer agent find search failed"); + break; + } +} + + +static void on_service_connection_terminated(sap_peer_agent_h peer_agent, + sap_socket_h socket, + sap_service_connection_result_e result, + void *user_data) { + switch (result) { + case SAP_CONNECTION_TERMINATED_REASON_PEER_DISCONNECTED: + dlog_print(DLOG_INFO, LOG_TAG, "disconnected because peer lost"); + break; + + case SAP_CONNECTION_TERMINATED_REASON_DEVICE_DETACHED: + dlog_print(DLOG_INFO, LOG_TAG, "disconnected because device is detached"); + break; + + default: + // fall through + case SAP_CONNECTION_TERMINATED_REASON_UNKNOWN: + dlog_print(DLOG_INFO, LOG_TAG, "disconnected because of unknown reason"); + break; + } + + sap_socket_destroy(priv_data.socket); + priv_data.socket = NULL; + agent_connected = FALSE; +} + + +static void on_data_recieved(sap_socket_h socket, + unsigned short int channel_id, + unsigned int payload_length, + void *buffer, + void *user_data) { + dlog_print(DLOG_INFO, LOG_TAG, "received data: %p, len:%d", buffer, payload_length); + + char* string_buffer = (char*) buffer; + if (string_buffer[0] == 'a') { + install_aids(buffer + sizeof(char), payload_length - 1); + } else if (string_buffer[0] == 'd') { + send_apdu_response(priv_data.nfc_handle, buffer + sizeof(char), payload_length - 1); + } +} + +gboolean send_data(nfc_se_h nfc_handle, char* prefix, unsigned int prefix_len, void *message, unsigned int message_len) { + gboolean result; + if (nfc_handle != NULL) { + priv_data.nfc_handle = nfc_handle; + } + void *final_message = malloc(prefix_len + message_len); + memcpy(final_message, prefix, prefix_len); + memcpy(final_message + prefix_len * sizeof(char), message, message_len); + result = sap_socket_send_data(priv_data.socket, + ACCESSORY_CHANNELID, prefix_len + message_len, final_message); + + if (result != SAP_RESULT_SUCCESS) { + dlog_print(DLOG_INFO, LOG_TAG, "couldn't send sap message: %d", result); + } + + free(final_message); + return result; +} + +gboolean request_installed_aids() { + return send_data(NULL, "a", 1, "", 0); +} + +static void on_service_connection_created(sap_peer_agent_h peer_agent, + sap_socket_h socket, + sap_service_connection_result_e result, + void *user_data) { + switch (result) { + case SAP_CONNECTION_SUCCESS: + dlog_print(DLOG_INFO, LOG_TAG, "peer agent connection is successful, pa :%u", peer_agent); + sap_peer_agent_set_service_connection_terminated_cb(priv_data.peer_agent, + on_service_connection_terminated, + NULL); + + sap_socket_set_data_received_cb(socket, on_data_recieved, peer_agent); + priv_data.socket = socket; + agent_connected = TRUE; + + request_installed_aids(); + break; + + case SAP_CONNECTION_ALREADY_EXIST: + dlog_print(DLOG_INFO, LOG_TAG, "connection already exists"); + priv_data.socket = socket; + agent_connected = TRUE; + break; + + case SAP_CONNECTION_FAILURE_DEVICE_UNREACHABLE: + dlog_print(DLOG_INFO, LOG_TAG, "device is not unreachable"); + break; + + case SAP_CONNECTION_FAILURE_INVALID_PEERAGENT: + dlog_print(DLOG_INFO, LOG_TAG, "invalid peer agent"); + break; + + case SAP_CONNECTION_FAILURE_NETWORK: + dlog_print(DLOG_INFO, LOG_TAG, "network failure"); + break; + + case SAP_CONNECTION_FAILURE_PEERAGENT_NO_RESPONSE: + dlog_print(DLOG_INFO, LOG_TAG, "peer agent is no response"); + break; + + case SAP_CONNECTION_FAILURE_PEERAGENT_REJECTED: + dlog_print(DLOG_INFO, LOG_TAG, "peer agent is rejected"); + break; + + case SAP_CONNECTION_FAILURE_UNKNOWN: + dlog_print(DLOG_INFO, LOG_TAG, "unknown error"); + break; + } +} + +static gboolean _create_service_connection(gpointer user_data) { + struct priv *priv = NULL; + sap_result_e result = SAP_RESULT_FAILURE; + + priv = (struct priv *)user_data; + result = sap_agent_request_service_connection(priv->agent, + priv->peer_agent, + on_service_connection_created, + NULL); + + if (result == SAP_RESULT_SUCCESS) { + dlog_print(DLOG_DEBUG, LOG_TAG, "req service conn call succeeded"); + } else { + dlog_print(DLOG_ERROR, LOG_TAG, "req service conn call is failed (%d)", result); + } + + return FALSE; +} + +gboolean request_service_connection(void) { + g_idle_add(_create_service_connection, &priv_data); + return TRUE; +} + +static gboolean _terminate_service_connection(gpointer user_data) { + struct priv *priv = NULL; + sap_result_e result = SAP_RESULT_FAILURE; + + priv = (struct priv *)user_data; + + if (priv->socket) + result = sap_peer_agent_terminate_service_connection(priv->peer_agent); + else { + return FALSE; + } + + if (result == SAP_RESULT_SUCCESS) { + dlog_print(DLOG_DEBUG, LOG_TAG, "terminate service conn call succeeded"); + + priv->socket = NULL; + agent_connected = FALSE; + } else { + dlog_print(DLOG_ERROR, LOG_TAG, "terminate service conn call is failed (%d)", result); + } + + return FALSE; +} + +gboolean terminate_service_connection(void) +{ + g_idle_add(_terminate_service_connection, &priv_data); + return TRUE; +} + +static gboolean _find_peer_agent(gpointer user_data) +{ + struct priv *priv = NULL; + sap_result_e result = SAP_RESULT_FAILURE; + + priv = (struct priv *)user_data; + + result = sap_agent_find_peer_agent(priv->agent, on_peer_agent_updated, NULL); + + if (result == SAP_RESULT_SUCCESS) { + dlog_print(DLOG_DEBUG, LOG_TAG, "find peer call succeeded"); + } else { + dlog_print(DLOG_ERROR, LOG_TAG, "find peer call failed (%d)", result); + } + + return FALSE; +} + +gboolean find_peers() +{ + g_idle_add(_find_peer_agent, &priv_data); + dlog_print(DLOG_DEBUG, LOG_TAG, "find peer called"); + return TRUE; +} + +static void on_agent_initialized(sap_agent_h agent, + sap_agent_initialized_result_e result, + void *user_data) +{ + switch (result) { + case SAP_AGENT_INITIALIZED_RESULT_SUCCESS: + dlog_print(DLOG_INFO, LOG_TAG, "agent is initialized"); + + priv_data.agent = agent; + agent_created = TRUE; + break; + + case SAP_AGENT_INITIALIZED_RESULT_DUPLICATED: + dlog_print(DLOG_INFO, LOG_TAG, "duplicate registration"); + break; + + case SAP_AGENT_INITIALIZED_RESULT_INVALID_ARGUMENTS: + dlog_print(DLOG_INFO, LOG_TAG, "invalid arguments"); + break; + + case SAP_AGENT_INITIALIZED_RESULT_INTERNAL_ERROR: + dlog_print(DLOG_INFO, LOG_TAG, "internal sap error"); + break; + + default: + dlog_print(DLOG_INFO, LOG_TAG, "unknown status (%d)", result); + break; + } +} + +static void on_device_status_changed(sap_device_status_e status, sap_transport_type_e transport_type, + void *user_data) +{ + switch (transport_type) { + case SAP_TRANSPORT_TYPE_BT: + dlog_print(DLOG_INFO, LOG_TAG, "connectivity type(%d): bt", transport_type); + break; + + case SAP_TRANSPORT_TYPE_BLE: + dlog_print(DLOG_INFO, LOG_TAG, "connectivity type(%d): ble", transport_type); + break; + + case SAP_TRANSPORT_TYPE_TCP: + dlog_print(DLOG_INFO, LOG_TAG, "connectivity type(%d): tcp/ip", transport_type); + break; + + case SAP_TRANSPORT_TYPE_USB: + dlog_print(DLOG_INFO, LOG_TAG, "connectivity type(%d): usb", transport_type); + break; + + case SAP_TRANSPORT_TYPE_MOBILE: + dlog_print(DLOG_INFO, LOG_TAG, "connectivity type(%d): mobile", transport_type); + break; + + default: + dlog_print(DLOG_INFO, LOG_TAG, "unknown connectivity type (%d)", transport_type); + break; + } + + switch (status) { + case SAP_DEVICE_STATUS_DETACHED: + + if (priv_data.peer_agent) { + sap_socket_destroy(priv_data.socket); + priv_data.socket = NULL; + sap_peer_agent_destroy(priv_data.peer_agent); + priv_data.peer_agent = NULL; + agent_connected = FALSE; + } + break; + + case SAP_DEVICE_STATUS_ATTACHED: + if (agent_created) { + g_idle_add(_find_peer_agent, &priv_data); + } + break; + + default: + dlog_print(DLOG_INFO, LOG_TAG, "unknown status (%d)", status); + break; + } +} + +gboolean agent_initialize() +{ + int result = 0, i = 1; + gboolean agent_initialized = TRUE; + + do { + if (i > 100) { + agent_initialized = FALSE; + break; + } + result = sap_agent_initialize(priv_data.agent, + ACCESSORY_PROFILE_ID, SAP_AGENT_ROLE_CONSUMER, + on_agent_initialized, NULL); + dlog_print(DLOG_DEBUG, LOG_TAG, "sap_agent_initialize >>> %d", result); + i++; + } while (result != SAP_RESULT_SUCCESS); + + return agent_initialized; +} + +void initialize_sap() +{ + sap_agent_h agent = NULL; + + sap_agent_create(&agent); + + if (agent == NULL) + dlog_print(DLOG_ERROR, LOG_TAG, "ERROR in creating agent"); + else + dlog_print(DLOG_INFO, LOG_TAG, "SUCCESSFULLY create sap agent"); + + priv_data.agent = agent; + + sap_set_device_status_changed_cb(on_device_status_changed, NULL); + + agent_initialize(); +} diff --git a/TCardEmulator/src/tcardemulator.c b/TCardEmulator/src/tcardemulator.c new file mode 100644 index 0000000..530092e --- /dev/null +++ b/TCardEmulator/src/tcardemulator.c @@ -0,0 +1,159 @@ +#include "tcardemulator.h" +#include "sap_app.h" +#include +#include +#include +#include +#include +#include + +typedef struct appdata { + +} appdata_s; + +static void hce_event_cb(nfc_se_h handle, nfc_hce_event_type_e event, unsigned char *apdu, unsigned int apdu_len, void *user_data) { + switch (event) { + case NFC_HCE_EVENT_DEACTIVATED: + dlog_print(DLOG_DEBUG, LOG_TAG, "received NFC_HCE_EVENT_DEACTIVATED event on NFC handle %d", handle); + break; + + case NFC_HCE_EVENT_ACTIVATED: + dlog_print(DLOG_DEBUG, LOG_TAG, "received NFC_HCE_EVENT_ACTIVATED event on NFC handle %d", handle); + if (!agent_connected) { + find_peers(); + } + break; + + case NFC_HCE_EVENT_APDU_RECEIVED: + dlog_print(DLOG_DEBUG, LOG_TAG, "received NFC_HCE_EVENT_APDU_RECEIVED event on NFC handle %d", handle); + if (agent_connected) { + send_data(handle, "d", 1, apdu, apdu_len); + } else { + dlog_print(DLOG_INFO, LOG_TAG, "couldn't send message on SAP channel because agent is not connected"); + } + break; + + default: + dlog_print(DLOG_DEBUG, LOG_TAG, "received unknown event on NFC handle %d", handle); + break; + } +} + +void register_aid(gpointer data) { + int result = nfc_se_register_aid(NFC_SE_TYPE_HCE, NFC_CARD_EMULATION_CATEGORY_OTHER, data); + if (result != NFC_ERROR_NONE) { + dlog_print(DLOG_ERROR, LOG_TAG, "nfc_se_register_aid for aid %s failed: %d", data, result); + } else { + dlog_print(DLOG_DEBUG, LOG_TAG, "nfc_se_register_aid for aid %s succeeded.", data); + } +} + +void install_aids(void *buffer, unsigned int buffer_size) { + gchar aid_string[buffer_size + 1]; + g_strlcpy(aid_string, (gchar *)buffer, buffer_size + 1); + + gchar **aid_buffer = g_strsplit(aid_string, ",", 0); + int i; + int aid_len = g_strv_length(aid_buffer); + for (i = 0; i < aid_len; i++) { + register_aid((gpointer)aid_buffer[i]); + } + g_strfreev(aid_buffer); +} + +void send_apdu_response(nfc_se_h handle, unsigned char *resp, unsigned int resp_len) { + dlog_print(DLOG_DEBUG, LOG_TAG, "sending data to nfc handle: %d", handle); + int result = nfc_hce_send_apdu_response(handle, resp, resp_len); + if (result != NFC_ERROR_NONE) { + dlog_print(DLOG_DEBUG, LOG_TAG, "error sending data to nfc handle %d: ", handle); + } +} + +bool service_app_create(void *data) { + int ret = NFC_ERROR_NONE; + bool r = false; + nfc_se_card_emulation_mode_type_e ce_type; + + ret = nfc_manager_initialize(); + if (ret != NFC_ERROR_NONE) { + dlog_print(DLOG_ERROR, LOG_TAG, "nfc_manager_initialize failed : %d", ret); + goto err; + } + + ret = nfc_se_get_card_emulation_mode(&ce_type); + if (ret != NFC_ERROR_NONE) { + dlog_print(DLOG_ERROR, LOG_TAG, "nfc_se_get_card_emulation_mode failed : %d", ret); + goto err; + } + + if (ce_type == NFC_SE_CARD_EMULATION_MODE_OFF) { + nfc_se_enable_card_emulation(); + if (ret != NFC_ERROR_NONE) { + dlog_print(DLOG_ERROR, LOG_TAG, "nfc_se_enable_card_emulation failed : %d", ret); + goto err; + } + } + + ret = nfc_manager_set_hce_event_cb(hce_event_cb, NULL); + if (ret != NFC_ERROR_NONE) { + dlog_print(DLOG_ERROR, LOG_TAG, "nfc_manager_set_hce_event_cb failed : %d", ret); + goto err; + } else { + dlog_print(DLOG_DEBUG, LOG_TAG, "nfc_manager_set_hce_event_cb succeeded"); + } + + initialize_sap(); + + find_peers(); + + r = true; + +err: + return r; +} + +void service_app_terminate(void *data) { + int ret = NFC_ERROR_NONE; + + nfc_manager_unset_hce_event_cb(); + + ret = nfc_manager_deinitialize(); + if (ret != NFC_ERROR_NONE) + { + dlog_print(DLOG_ERROR, LOG_TAG, "nfc_manager_deinitialize failed : %d", ret); + } + + terminate_service_connection(); + + return; +} + +void service_app_control(app_control_h app_control, void *data) { + return; +} + +void service_app_low_memory(void *data) { + service_app_terminate(&data); + + return; +} + +void service_app_low_battery(void *data) { + service_app_terminate(&data); + + return; +} + +int main(int argc, char* argv[]) { + appdata_s ad = {}; + + service_app_event_callback_s event_callback; + + event_callback.create = service_app_create; + event_callback.terminate = service_app_terminate; + event_callback.app_control = service_app_control; + event_callback.low_memory = service_app_low_memory; + event_callback.low_battery = service_app_low_battery; + + return svc_app_main(argc, argv, &event_callback, &ad); +} diff --git a/TCardEmulator/tizen-manifest.xml b/TCardEmulator/tizen-manifest.xml new file mode 100644 index 0000000..f099c89 --- /dev/null +++ b/TCardEmulator/tizen-manifest.xml @@ -0,0 +1,15 @@ + + + + + + ic_launcher.png + + + + + http://developer.samsung.com/tizen/privilege/accessoryprotocol + http://tizen.org/privilege/nfc.cardemulation + + true +