Skip to content

Commit 1eaf5a1

Browse files
authored
Merge pull request #187 from ph4r05/pr/002-upgrade-android
Improve remote-reader
2 parents 0540c45 + dc314e7 commit 1eaf5a1

File tree

14 files changed

+191
-52
lines changed

14 files changed

+191
-52
lines changed

remote-reader/app/build.gradle

+12-12
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
apply plugin: 'com.android.application'
22

33
android {
4-
compileSdkVersion 23
5-
buildToolsVersion "23.0.1"
4+
compileSdkVersion 29
5+
buildToolsVersion "23.0.3"
66

77
defaultConfig {
88
applicationId "com.vsmartcard.remotesmartcardreader.app"
99
// NFC reader mode was added in KitKat
1010
minSdkVersion 19
11-
targetSdkVersion 23
11+
targetSdkVersion 29
1212
versionCode 6
1313
versionName "2.2"
1414
}
@@ -38,7 +38,7 @@ android.applicationVariants.all { variant ->
3838
} else {
3939
newApkName = "${appName}-${output.baseName}-${variant.versionName}-unaligned.apk"
4040
}
41-
output.outputFile = new File(output.outputFile.parent, newApkName)
41+
//output.outputFile = new File(output.outputFile.parent, newApkName)
4242
}
4343
}
4444

@@ -47,12 +47,12 @@ repositories {
4747
}
4848

4949
dependencies {
50-
compile fileTree(dir: 'libs', include: ['*.jar'])
51-
testCompile 'junit:junit:4.12'
52-
compile 'com.android.support:appcompat-v7:23.2.1'
53-
compile 'com.android.support:design:23.2.1'
54-
compile 'com.android.support:support-v4:23.2.1'
55-
56-
compile 'com.journeyapps:zxing-android-embedded:3.2.0@aar'
57-
compile 'com.google.zxing:core:3.2.1'
50+
implementation fileTree(dir: 'libs', include: ['*.jar'])
51+
testImplementation 'junit:junit:4.12'
52+
implementation 'androidx.appcompat:appcompat:1.2.0'
53+
implementation 'com.google.android.material:material:1.3.0'
54+
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
55+
56+
implementation 'com.journeyapps:zxing-android-embedded:3.2.0@aar'
57+
implementation 'com.google.zxing:core:3.2.1'
5858
}

remote-reader/app/src/main/java/com/example/android/common/logger/LogFragment.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333

3434
import android.graphics.Typeface;
3535
import android.os.Bundle;
36-
import android.support.v4.app.Fragment;
3736
import android.text.Editable;
3837
import android.text.TextWatcher;
3938
import android.view.Gravity;
@@ -42,6 +41,8 @@
4241
import android.view.ViewGroup;
4342
import android.widget.ScrollView;
4443

44+
import androidx.fragment.app.Fragment;
45+
4546
/**
4647
* Simple fraggment which contains a LogView and uses is to output log data it receives
4748
* through the LogNode interface.

remote-reader/app/src/main/java/com/vsmartcard/remotesmartcardreader/app/AppCompatPreferenceActivity.java

+6-5
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,16 @@
33
import android.content.res.Configuration;
44
import android.os.Bundle;
55
import android.preference.PreferenceActivity;
6-
import android.support.annotation.LayoutRes;
7-
import android.support.annotation.Nullable;
8-
import android.support.v7.app.ActionBar;
9-
import android.support.v7.app.AppCompatDelegate;
10-
import android.support.v7.widget.Toolbar;
116
import android.view.MenuInflater;
127
import android.view.View;
138
import android.view.ViewGroup;
149

10+
import androidx.annotation.LayoutRes;
11+
import androidx.annotation.Nullable;
12+
import androidx.appcompat.app.ActionBar;
13+
import androidx.appcompat.app.AppCompatDelegate;
14+
import androidx.appcompat.widget.Toolbar;
15+
1516
/**
1617
* A {@link android.preference.PreferenceActivity} which implements and proxies the necessary calls
1718
* to be used with AppCompat.

remote-reader/app/src/main/java/com/vsmartcard/remotesmartcardreader/app/MainActivity.java

+12-9
Original file line numberDiff line numberDiff line change
@@ -31,20 +31,21 @@
3131
import android.os.Bundle;
3232
import android.preference.PreferenceManager;
3333
import android.provider.Settings;
34-
import android.support.design.widget.FloatingActionButton;
35-
import android.support.design.widget.Snackbar;
36-
import android.support.v7.app.AlertDialog;
37-
import android.support.v7.app.AppCompatActivity;
38-
import android.support.v7.widget.Toolbar;
3934
import android.view.Menu;
4035
import android.view.MenuItem;
4136
import android.view.View;
4237

38+
import androidx.appcompat.app.AlertDialog;
39+
import androidx.appcompat.app.AppCompatActivity;
40+
import androidx.appcompat.widget.Toolbar;
41+
4342
import com.example.android.common.logger.Log;
4443
import com.example.android.common.logger.LogFragment;
4544
import com.example.android.common.logger.LogWrapper;
4645
import com.example.android.common.logger.MessageOnlyLogFilter;
4746

47+
import com.google.android.material.floatingactionbutton.FloatingActionButton;
48+
import com.google.android.material.snackbar.Snackbar;
4849
import com.vsmartcard.remotesmartcardreader.app.screaders.*;
4950

5051
@TargetApi(Build.VERSION_CODES.KITKAT)
@@ -197,11 +198,12 @@ public void onTagDiscovered(Tag tag) {
197198
}
198199

199200
private void vpcdConnect(SCReader scReader) {
200-
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(this);
201-
int port = Integer.parseInt(SP.getString("port", Integer.toString(VPCDWorker.DEFAULT_PORT)));
202-
String hostname = SP.getString("hostname", VPCDWorker.DEFAULT_HOSTNAME);
201+
final SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(this);
202+
final int port = Integer.parseInt(SP.getString("port", Integer.toString(VPCDWorker.DEFAULT_PORT)));
203+
final String hostname = SP.getString("hostname", VPCDWorker.DEFAULT_HOSTNAME);
204+
final boolean listen = SP.getBoolean("listen", VPCDWorker.DEFAULT_LISTEN);
203205
vpcdTest = new VPCDWorker();
204-
vpcdTest.execute(new VPCDWorker.VPCDWorkerParams(hostname, port, scReader));
206+
vpcdTest.execute(new VPCDWorker.VPCDWorkerParams(hostname, port, scReader, listen));
205207
}
206208

207209
private void vpcdDisconnect() {
@@ -231,6 +233,7 @@ public void onResume() {
231233
@Override
232234
public void onNewIntent(Intent intent) {
233235
// onResume gets called after this to handle the intent
236+
super.onNewIntent(intent);
234237
setIntent(intent);
235238
}
236239

remote-reader/app/src/main/java/com/vsmartcard/remotesmartcardreader/app/MyLogFragment.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@
2323
import android.content.ClipboardManager;
2424
import android.content.Context;
2525
import android.os.Bundle;
26-
import android.support.design.widget.Snackbar;
2726
import android.view.Menu;
2827
import android.view.MenuInflater;
2928
import android.view.MenuItem;
3029

3130
import com.example.android.common.logger.LogFragment;
31+
import com.google.android.material.snackbar.Snackbar;
3232

3333
public class MyLogFragment extends LogFragment {
3434

remote-reader/app/src/main/java/com/vsmartcard/remotesmartcardreader/app/SettingsActivity.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,13 @@
3232
import android.preference.Preference;
3333
import android.preference.PreferenceActivity;
3434
import android.provider.Settings;
35-
import android.support.design.widget.Snackbar;
36-
import android.support.v7.app.ActionBar;
3735
import android.preference.PreferenceFragment;
3836
import android.preference.PreferenceManager;
3937
import android.view.MenuItem;
38+
39+
import androidx.appcompat.app.ActionBar;
40+
41+
import com.google.android.material.snackbar.Snackbar;
4042
import com.google.zxing.integration.android.IntentIntegrator;
4143
import com.google.zxing.integration.android.IntentResult;
4244

remote-reader/app/src/main/java/com/vsmartcard/remotesmartcardreader/app/VPCDWorker.java

+120-7
Original file line numberDiff line numberDiff line change
@@ -20,35 +20,49 @@
2020
package com.vsmartcard.remotesmartcardreader.app;
2121

2222
import android.os.AsyncTask;
23-
import android.support.annotation.Nullable;
23+
24+
import androidx.annotation.Nullable;
2425

2526
import com.example.android.common.logger.Log;
2627
import com.vsmartcard.remotesmartcardreader.app.screaders.SCReader;
2728

2829
import java.io.IOException;
2930
import java.io.InputStream;
3031
import java.io.OutputStream;
32+
import java.net.Inet4Address;
3133
import java.net.InetAddress;
34+
import java.net.InterfaceAddress;
35+
import java.net.NetworkInterface;
36+
import java.net.ServerSocket;
3237
import java.net.Socket;
38+
import java.net.SocketTimeoutException;
39+
import java.util.Enumeration;
40+
import java.util.LinkedList;
41+
import java.util.List;
42+
import java.util.concurrent.TimeUnit;
3343

3444
class VPCDWorker extends AsyncTask<VPCDWorker.VPCDWorkerParams, Void, Void> {
3545

3646
public static class VPCDWorkerParams {
3747
final String hostname;
3848
final int port;
3949
final SCReader reader;
40-
VPCDWorkerParams(String hostname, int port, SCReader reader) {
50+
final boolean listen;
51+
VPCDWorkerParams(String hostname, int port, SCReader reader, boolean listen) {
4152
this.hostname = hostname;
4253
this.port = port;
4354
this.reader = reader;
55+
this.listen = listen;
4456
}
4557
}
4658

4759
public static final int DEFAULT_PORT = 35963;
4860
// default URI when used in emulator
4961
public static final String DEFAULT_HOSTNAME = "10.0.2.2";
62+
public static final boolean DEFAULT_LISTEN = false;
5063

5164
private SCReader reader;
65+
private ServerSocket listenSocket;
5266
private Socket socket;
5367
private InputStream inputStream;
5468
private OutputStream outputStream;
@@ -74,15 +88,22 @@ protected void onCancelled () {
7488
public Void doInBackground(VPCDWorkerParams... params) {
7589
try {
7690
reader = params[0].reader;
77-
Log.i(this.getClass().getName(), "Connecting to " + params[0].hostname + ":" + Integer.toString(params[0].port) + "...");
78-
vpcdConnect(params[0].hostname, params[0].port);
79-
Log.i(this.getClass().getName(), "Connected to VPCD");
91+
vpcdConnection(params[0]);
8092

8193
while (!isCancelled()) {
94+
vpcdAccept();
8295
byte[] out = null;
8396
byte[] in = receiveFromVPCD();
84-
if (in == null)
85-
break;
97+
if (in == null) {
98+
if (listenSocket == null) {
99+
Log.i(this.getClass().getName(), "End of stream, finishing");
100+
break;
101+
} else {
102+
Log.i(this.getClass().getName(), "End of stream, closing connection");
103+
vpcdCloseClient();
104+
continue; // back to accept
105+
}
106+
}
86107

87108
if (in.length == VPCD_CTRL_LEN) {
88109
switch (in[0]) {
@@ -168,7 +189,79 @@ private void sendToVPCD(byte[] data) throws IOException {
168189
outputStream.flush();
169190
}
170191

192+
private void vpcdConnection(VPCDWorkerParams params) throws IOException {
193+
if (params.listen){
194+
vpcdListen(params.port);
195+
return;
196+
}
197+
198+
Log.i(this.getClass().getName(), "Connecting to " + params.hostname + ":" + Integer.toString(params.port) + "...");
199+
vpcdConnect(params.hostname, params.port);
200+
Log.i(this.getClass().getName(), "Connected to VPCD");
201+
}
202+
203+
private void vpcdListen(int port) throws IOException {
204+
listenSocket = new ServerSocket(port);
205+
206+
final List<String> ifaceAddresses = new LinkedList<>();
207+
final Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
208+
while(ifaces.hasMoreElements()){
209+
final NetworkInterface iface = ifaces.nextElement();
210+
if (!iface.isUp() || iface.isLoopback() || iface.isVirtual()) {
211+
continue;
212+
}
213+
for(InterfaceAddress addr : iface.getInterfaceAddresses()){
214+
final InetAddress inetAddr = addr.getAddress();
215+
ifaceAddresses.add(inetAddr.getHostAddress());
216+
}
217+
}
218+
219+
Log.i(this.getClass().getName(), "Listening on port " + port + ". Local addresses: " + join(", ", ifaceAddresses));
220+
}
221+
222+
private void vpcdAccept() throws IOException {
223+
if(listenSocket == null){
224+
return;
225+
}
226+
227+
if (socket != null){
228+
return; // Already accepted, only one client allowed
229+
}
230+
231+
Log.i(this.getClass().getName(),"Waiting for connections...");
232+
while(!isCancelled()) {
233+
listenSocket.setSoTimeout(1000);
234+
try {
235+
socket = listenSocket.accept();
236+
} catch (SocketTimeoutException ignored){}
237+
if (socket != null){
238+
break;
239+
}
240+
}
241+
242+
Log.i(this.getClass().getName(),"Connected, " + socket.getInetAddress());
243+
listenSocket.setSoTimeout(0);
244+
outputStream = socket.getOutputStream();
245+
inputStream = socket.getInputStream();
246+
}
247+
248+
private void vpcdCloseClient(){
249+
try {
250+
outputStream.close();
251+
} catch (IOException ignored) { }
252+
try {
253+
inputStream.close();
254+
} catch (IOException ignored) { }
255+
try {
256+
socket.close();
257+
} catch (IOException ignored) { }
258+
outputStream = null;
259+
inputStream = null;
260+
socket = null;
261+
}
262+
171263
private void vpcdConnect(String hostname, int port) throws IOException {
264+
listenSocket = null;
172265
socket = new Socket(InetAddress.getByName(hostname), port);
173266
outputStream = socket.getOutputStream();
174267
inputStream = socket.getInputStream();
@@ -182,5 +275,25 @@ private void vpcdDisconnect() throws IOException {
182275
socket.close();
183276
Log.i(this.getClass().getName(), "Disconnected from VPCD");
184277
}
278+
if (listenSocket != null) {
279+
Log.i(this.getClass().getName(), "Closing listening socket");
280+
listenSocket.close();
281+
}
282+
}
283+
284+
/**
285+
* Usage of API level 24+ would allow streams(), join can be removed.
286+
*/
287+
private static String join(String separator, List<String> input) {
288+
if (input == null || input.size() <= 0) return "";
289+
StringBuilder sb = new StringBuilder();
290+
for (int i = 0; i < input.size(); i++) {
291+
sb.append(input.get(i));
292+
if (i != input.size() - 1) {
293+
sb.append(separator);
294+
}
295+
}
296+
return sb.toString();
297+
185298
}
186299
}

0 commit comments

Comments
 (0)