added proper separation between JCardSim and VICC

Aditionally use the wording emulator within this project to not be
confused with JCardSim's Simulator classes.
This commit is contained in:
Frank Morgner
2016-05-13 08:30:56 +02:00
parent 8517cea801
commit 4d9e27858a
8 changed files with 409 additions and 367 deletions

View File

@@ -37,7 +37,7 @@
</intent-filter>
</activity>
<service android:name="com.vsmartcard.acardemulator.SimulatorService"
<service android:name=".EmulatorService"
android:exported="true"
android:permission="android.permission.BIND_NFC_SERVICE">
<intent-filter>

View File

@@ -0,0 +1,128 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.vsmartcard.acardemulator;
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.preference.PreferenceManager;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
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 {
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";
public static final String EXTRA_ERROR = "MSG_ERROR";
public static final String EXTRA_DESELECT = "MSG_DESELECT";
public static final String EXTRA_INSTALL = "MSG_INSTALL";
private static Emulator emulator = null;
private static boolean do_destroy = false;
@Override
public void onCreate () {
super.onCreate();
// force reloading applets if requested
do_destroy();
if (emulator == null) {
Log.d("", "Begin transaction");
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(this);
String str_emulator = SP.getString("emulator", "");
if (str_emulator.equals(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,
SP.getBoolean("activate_helloworld", false),
SP.getBoolean("activate_openpgp", false),
SP.getBoolean("activate_oath", false),
SP.getBoolean("activate_isoapplet", false),
SP.getBoolean("activate_gidsapplet", false));
}
}
}
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) {
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);
return rapdu;
}
@Override
public void onDeactivated(int reason) {
Intent i = new Intent(TAG);
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;
}
LocalBroadcastManager.getInstance(this).sendBroadcast(i);
}
}

View File

@@ -48,12 +48,12 @@ public class MainActivity extends AppCompatActivity {
private BroadcastReceiver bReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(SimulatorService.TAG)) {
String capdu = intent.getStringExtra(SimulatorService.EXTRA_CAPDU);
String rapdu = intent.getStringExtra(SimulatorService.EXTRA_RAPDU);
String error = intent.getStringExtra(SimulatorService.EXTRA_ERROR);
String deselect = intent.getStringExtra(SimulatorService.EXTRA_DESELECT);
String install = intent.getStringExtra(SimulatorService.EXTRA_INSTALL);
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 (install != null)
textViewVPCDStatus.append(getResources().getString(R.string.status_install) + ":" + install + "\n");
if (capdu != null)
@@ -102,7 +102,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();
SimulatorService.destroySimulator(getApplicationContext());
EmulatorService.destroySimulator(getApplicationContext());
}
}
});
@@ -116,7 +116,7 @@ public class MainActivity extends AppCompatActivity {
LocalBroadcastManager bManager = LocalBroadcastManager.getInstance(this);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(SimulatorService.TAG);
intentFilter.addAction(EmulatorService.TAG);
bManager.registerReceiver(bReceiver, intentFilter);
}

View File

@@ -21,7 +21,6 @@ package com.vsmartcard.acardemulator;
import android.annotation.TargetApi;
import android.app.FragmentTransaction;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@@ -41,6 +40,7 @@ import android.view.MenuItem;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
import com.vsmartcard.acardemulator.emulators.VICCEmulator;
/**
* A {@link PreferenceActivity} that presents a set of application settings. On
@@ -230,7 +230,7 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
h = uri.getHost();
int _p = uri.getPort();
if (_p < 0) {
_p = SimulatorService.DEFAULT_PORT;
_p = VICCEmulator.DEFAULT_PORT;
}
p = Integer.toString(_p);
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(this);

View File

@@ -1,356 +0,0 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.vsmartcard.acardemulator;
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.preference.PreferenceManager;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import com.licel.jcardsim.base.Simulator;
import com.licel.jcardsim.base.SimulatorRuntime;
import com.licel.jcardsim.samples.HelloWorldApplet;
import com.licel.jcardsim.utils.AIDUtil;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import openpgpcard.OpenPGPApplet;
import pkgYkneoOath.YkneoOath;
import net.pwendland.javacard.pki.isoapplet.IsoApplet;
import com.mysmartlogon.gidsApplet.GidsApplet;
public class SimulatorService extends HostApduService {
public static final int DEFAULT_PORT = 35963;
private static final String DEFAULT_HOSTNAME = "10.0.2.2";
private static Socket socket;
private static InputStream inputStream;
private static OutputStream outputStream;
public static final String TAG = "com.vsmartcard.acardemulator.SimulatorService";
public static final String EXTRA_CAPDU = "MSG_CAPDU";
public static final String EXTRA_RAPDU = "MSG_RAPDU";
public static final String EXTRA_ERROR = "MSG_ERROR";
public static final String EXTRA_DESELECT = "MSG_DESELECT";
public static final String EXTRA_INSTALL = "MSG_INSTALL";
private static Simulator simulator = null;
private static boolean do_destroy = false;
private boolean useVPCD() {
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(this);
String emulator = SP.getString("emulator", "");
if (emulator.equals(getString(R.string.vicc)))
return true;
return false;
}
private int port() {
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(this);
return Integer.parseInt(SP.getString("port", Integer.toString(DEFAULT_PORT)));
}
private String hostname() {
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(this);
return SP.getString("hostname", DEFAULT_HOSTNAME);
}
private void createSimulator() {
String aid, name, extra_install = "", extra_error = "";
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(this);
simulator = new Simulator(new SimulatorRuntime());
if (SP.getBoolean("activate_helloworld", false)) {
name = getResources().getString(R.string.applet_helloworld);
aid = getResources().getString(R.string.aid_helloworld);
try {
simulator.installApplet(AIDUtil.create(aid), HelloWorldApplet.class);
extra_install += "\n" + name + " (AID: " + aid + ")";
} catch (Exception e) {
e.printStackTrace();
extra_error += "\n" + "Could not install " + name + " (AID: " + aid + ")";
}
}
if (SP.getBoolean("activate_openpgp", false)) {
name = getResources().getString(R.string.applet_openpgp);
aid = getResources().getString(R.string.aid_openpgp);
try {
byte[] aid_bytes = Util.hexStringToByteArray(aid);
byte[] inst_params = new byte[aid.length() + 1];
inst_params[0] = (byte) aid_bytes.length;
System.arraycopy(aid_bytes, 0, inst_params, 1, aid_bytes.length);
simulator.installApplet(AIDUtil.create(aid), OpenPGPApplet.class, inst_params, (short) 0, (byte) inst_params.length);
extra_install += "\n" + name + " (AID: " + aid + ")";
} catch (Exception e) {
e.printStackTrace();
extra_error += "\n" + "Could not install " + name + " (AID: " + aid + ")";
}
}
if (SP.getBoolean("activate_oath", false)) {
name = getResources().getString(R.string.applet_oath);
aid = getResources().getString(R.string.aid_oath);
try {
byte[] aid_bytes = Util.hexStringToByteArray(aid);
byte[] inst_params = new byte[aid.length() + 1];
inst_params[0] = (byte) aid_bytes.length;
System.arraycopy(aid_bytes, 0, inst_params, 1, aid_bytes.length);
simulator.installApplet(AIDUtil.create(aid), YkneoOath.class, inst_params, (short) 0, (byte) inst_params.length);
extra_install += "\n" + name + " (AID: " + aid + ")";
} catch (Exception e) {
e.printStackTrace();
extra_error += "\n" + "Could not install " + name + " (AID: " + aid + ")";
}
}
if (SP.getBoolean("activate_isoapplet", false)) {
name = getResources().getString(R.string.applet_isoapplet);
aid = getResources().getString(R.string.aid_isoapplet);
try {
simulator.installApplet(AIDUtil.create(aid), IsoApplet.class);
extra_install += "\n" + name + " (AID: " + aid + ")";
} catch (Exception e) {
e.printStackTrace();
extra_error += "\n" + "Could not install " + name + " (AID: " + aid + ")";
}
}
if (SP.getBoolean("activate_gidsapplet", false)) {
name = getResources().getString(R.string.applet_gidsapplet);
aid = getResources().getString(R.string.aid_gidsapplet);
try {
simulator.installApplet(AIDUtil.create(aid), GidsApplet.class);
extra_install += "\n" + name + " (AID: " + aid + ")";
} catch (Exception e) {
e.printStackTrace();
extra_error += "\n" + "Could not install " + name + " (AID: " + aid + ")";
}
}
Intent i = new Intent(TAG);
if (!extra_error.isEmpty())
i.putExtra(EXTRA_ERROR, extra_error);
if (!extra_install.isEmpty())
i.putExtra(EXTRA_INSTALL, extra_install);
LocalBroadcastManager.getInstance(this).sendBroadcast(i);
}
@Override
public void onCreate () {
super.onCreate();
// force reloading applets if requested
do_destroy();
Log.d("", "Begin transaction");
if (useVPCD()) {
if (socket == null) {
try {
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
vpcdConnect();
sendPowerOn();
} catch (IOException e) {
e.printStackTrace();
vpcdDisconnect();
}
}
} else {
if (simulator == null)
createSimulator();
}
}
public static void destroySimulator(Context context) {
do_destroy = true;
}
private void do_destroy() {
if (do_destroy) {
simulator = 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) {
Intent i = new Intent(TAG);
String extra_error = "";
byte[] rapdu = null;
i.putExtra(EXTRA_CAPDU, Util.byteArrayToHexString(capdu));
try {
if (useVPCD()) {
rapdu = transmit(capdu);
} else {
rapdu = simulator.transmitCommand(capdu);
}
if (rapdu != null)
i.putExtra(EXTRA_RAPDU, Util.byteArrayToHexString(rapdu));
} catch (Exception e) {
e.printStackTrace();
vpcdDisconnect();
extra_error += "Internal error";
}
if (!extra_error.isEmpty())
i.putExtra(EXTRA_ERROR, extra_error);
LocalBroadcastManager.getInstance(this).sendBroadcast(i);
return rapdu;
}
@Override
public void onDeactivated(int reason) {
Intent i = new Intent(TAG);
Log.d("", "End transaction");
switch (reason) {
case DEACTIVATION_LINK_LOSS:
i.putExtra(EXTRA_DESELECT, "link lost");
if (useVPCD())
try {
sendPowerOff();
} catch (IOException e) {
e.printStackTrace();
vpcdDisconnect();
}
break;
case DEACTIVATION_DESELECTED:
i.putExtra(EXTRA_DESELECT, "deactivated");
if (useVPCD())
try {
sendReset();
} catch (IOException e) {
e.printStackTrace();
vpcdDisconnect();
}
break;
}
if (useVPCD()) {
//vpcdDisconnect();
}
LocalBroadcastManager.getInstance(this).sendBroadcast(i);
}
private byte[] receiveFromVPCD() throws IOException {
/* convert length from network byte order.
Note that Java always uses network byte order internally. */
int length1 = inputStream.read();
int length2 = inputStream.read();
if (length1 == -1 || length2 == -1) {
// EOF
return null;
}
int length = (length1 << 8) + length2;
byte[] data = new byte[length];
int offset = 0;
while (length > 0) {
int read = inputStream.read(data, offset, length);
if (read == -1) {
// EOF
return null;
}
offset += read;
length -= read;
}
return data;
}
private byte[] transmit(byte[] capdu) throws IOException {
sendToVPCD(capdu);
return receiveFromVPCD();
}
private void sendPowerOff() throws IOException {
Log.d("", "Power Off");
sendToVPCD(new byte[] {0x00});
}
private void sendPowerOn() throws IOException {
Log.d("", "Power On");
sendToVPCD(new byte[] {0x01});
}
private void sendReset() throws IOException {
Log.d("", "Reset");
sendToVPCD(new byte[] {0x02});
}
private void sendToVPCD(byte[] data) throws IOException {
/* convert length to network byte order.
Note that Java always uses network byte order internally. */
byte[] length = new byte[2];
length[0] = (byte) (data.length >> 8);
length[1] = (byte) (data.length & 0xff);
outputStream.write(length);
outputStream.write(data, 0, data.length);
outputStream.flush();
}
private void vpcdConnect() throws IOException {
String hostname = hostname();
int port = port();
Log.d("", "Connecting to " + hostname + ":" + Integer.toString(port));
socket = new Socket(InetAddress.getByName(hostname), port);
outputStream = socket.getOutputStream();
inputStream = socket.getInputStream();
}
private void vpcdDisconnect() {
Log.d("", "Disconnecting");
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
// ignore
} finally {
socket = null;
}
}
}
}

View File

@@ -0,0 +1,11 @@
package com.vsmartcard.acardemulator.emulators;
public interface Emulator {
public void deactivate();
public void destroy();
public byte[] process(byte[] commandAPDU);
}

View File

@@ -0,0 +1,125 @@
package com.vsmartcard.acardemulator.emulators;
import android.content.Context;
import android.content.Intent;
import android.support.v4.content.LocalBroadcastManager;
import com.licel.jcardsim.base.Simulator;
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;
import net.pwendland.javacard.pki.isoapplet.IsoApplet;
import openpgpcard.OpenPGPApplet;
import pkgYkneoOath.YkneoOath;
public class JCEmulator implements Emulator {
private static Simulator simulator = null;
public JCEmulator(
Context context,
boolean activate_helloworld,
boolean activate_openpgp,
boolean activate_oath,
boolean activate_isoapplet,
boolean activate_gidsapplet) {
String aid, name, extra_install = "", extra_error = "";
simulator = new Simulator(new SimulatorRuntime());
if (activate_helloworld) {
name = context.getResources().getString(R.string.applet_helloworld);
aid = context.getResources().getString(R.string.aid_helloworld);
try {
simulator.installApplet(AIDUtil.create(aid), HelloWorldApplet.class);
extra_install += "\n" + name + " (AID: " + aid + ")";
} catch (Exception e) {
e.printStackTrace();
extra_error += "\n" + "Could not install " + name + " (AID: " + aid + ")";
}
}
if (activate_openpgp) {
name = context.getResources().getString(R.string.applet_openpgp);
aid = context.getResources().getString(R.string.aid_openpgp);
try {
byte[] aid_bytes = Util.hexStringToByteArray(aid);
byte[] inst_params = new byte[aid.length() + 1];
inst_params[0] = (byte) aid_bytes.length;
System.arraycopy(aid_bytes, 0, inst_params, 1, aid_bytes.length);
simulator.installApplet(AIDUtil.create(aid), OpenPGPApplet.class, inst_params, (short) 0, (byte) inst_params.length);
extra_install += "\n" + name + " (AID: " + aid + ")";
} catch (Exception e) {
e.printStackTrace();
extra_error += "\n" + "Could not install " + name + " (AID: " + aid + ")";
}
}
if (activate_oath) {
name = context.getResources().getString(R.string.applet_oath);
aid = context.getResources().getString(R.string.aid_oath);
try {
byte[] aid_bytes = Util.hexStringToByteArray(aid);
byte[] inst_params = new byte[aid.length() + 1];
inst_params[0] = (byte) aid_bytes.length;
System.arraycopy(aid_bytes, 0, inst_params, 1, aid_bytes.length);
simulator.installApplet(AIDUtil.create(aid), YkneoOath.class, inst_params, (short) 0, (byte) inst_params.length);
extra_install += "\n" + name + " (AID: " + aid + ")";
} catch (Exception e) {
e.printStackTrace();
extra_error += "\n" + "Could not install " + name + " (AID: " + aid + ")";
}
}
if (activate_isoapplet) {
name = context.getResources().getString(R.string.applet_isoapplet);
aid = context.getResources().getString(R.string.aid_isoapplet);
try {
simulator.installApplet(AIDUtil.create(aid), IsoApplet.class);
extra_install += "\n" + name + " (AID: " + aid + ")";
} catch (Exception e) {
e.printStackTrace();
extra_error += "\n" + "Could not install " + name + " (AID: " + aid + ")";
}
}
if (activate_gidsapplet) {
name = context.getResources().getString(R.string.applet_gidsapplet);
aid = context.getResources().getString(R.string.aid_gidsapplet);
try {
simulator.installApplet(AIDUtil.create(aid), GidsApplet.class);
extra_install += "\n" + name + " (AID: " + aid + ")";
} catch (Exception e) {
e.printStackTrace();
extra_error += "\n" + "Could not install " + name + " (AID: " + aid + ")";
}
}
Intent i = new Intent(EmulatorService.TAG);
if (!extra_error.isEmpty())
i.putExtra(EmulatorService.EXTRA_ERROR, extra_error);
if (!extra_install.isEmpty())
i.putExtra(EmulatorService.EXTRA_INSTALL, extra_install);
LocalBroadcastManager.getInstance(context).sendBroadcast(i);
}
public void destroy() {
if (simulator != null) {
simulator.reset();
simulator = null;
}
}
public byte[] process(byte[] commandAPDU) {
return simulator.transmitCommand(commandAPDU);
}
public void deactivate() {
simulator.reset();
}
}

View File

@@ -0,0 +1,134 @@
package com.vsmartcard.acardemulator.emulators;
import android.os.StrictMode;
import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
public class VICCEmulator implements Emulator {
public static final int DEFAULT_PORT = 35963;
public static final String DEFAULT_HOSTNAME = "10.0.2.2";
private static Socket socket;
private static InputStream inputStream;
private static OutputStream outputStream;
public VICCEmulator(String hostname, int port) {
if (socket == null) {
try {
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
vpcdConnect(hostname, port);
sendPowerOn();
} catch (IOException e) {
e.printStackTrace();
vpcdDisconnect();
}
}
}
@Override
public void deactivate() {
try {
sendPowerOff();
} catch (IOException e) {
e.printStackTrace();
vpcdDisconnect();
}
}
@Override
public void destroy() {
vpcdDisconnect();
}
@Override
public byte[] process(byte[] commandAPDU) {
try {
sendToVPCD(commandAPDU);
return receiveFromVPCD();
} catch (IOException e) {
e.printStackTrace();
}
return new byte[] {0x6D, 0x00};
}
private void sendPowerOff() throws IOException {
Log.d("", "Power Off");
sendToVPCD(new byte[] {0x00});
}
private void sendPowerOn() throws IOException {
Log.d("", "Power On");
sendToVPCD(new byte[] {0x01});
}
private void sendReset() throws IOException {
Log.d("", "Reset");
sendToVPCD(new byte[] {0x02});
}
private byte[] receiveFromVPCD() throws IOException {
/* convert length from network byte order.
Note that Java always uses network byte order internally. */
int length1 = inputStream.read();
int length2 = inputStream.read();
if (length1 == -1 || length2 == -1) {
// EOF
return null;
}
int length = (length1 << 8) + length2;
byte[] data = new byte[length];
int offset = 0;
while (length > 0) {
int read = inputStream.read(data, offset, length);
if (read == -1) {
// EOF
return null;
}
offset += read;
length -= read;
}
return data;
}
private void sendToVPCD(byte[] data) throws IOException {
/* convert length to network byte order.
Note that Java always uses network byte order internally. */
byte[] length = new byte[2];
length[0] = (byte) (data.length >> 8);
length[1] = (byte) (data.length & 0xff);
outputStream.write(length);
outputStream.write(data, 0, data.length);
outputStream.flush();
}
private void vpcdConnect(String hostname, int port) throws IOException {
Log.d("", "Connecting to " + hostname + ":" + Integer.toString(port));
socket = new Socket(InetAddress.getByName(hostname), port);
outputStream = socket.getOutputStream();
inputStream = socket.getInputStream();
}
private void vpcdDisconnect() {
Log.d("", "Disconnecting");
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
// ignore
} finally {
socket = null;
}
}
}
}