Skip to content

Commit f00b0c2

Browse files
committed
ANDROID: add tool to generate SB qrcodes
1 parent 5858a69 commit f00b0c2

File tree

20 files changed

+207
-14
lines changed

20 files changed

+207
-14
lines changed

ChangeLog

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
2014-06-11
2+
Android changes:
3+
- Run by URL/QrCode.
4+
- Implemented BEEP/SOUND
5+
- Screen layout adjusts when virtual keypad displayed
6+
17
2014-04-20
28
Released Windows version 0.11.5
39

src/platform/android/jni/runtime.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -409,9 +409,10 @@ void Runtime::handleKeyEvent(MAEvent &event) {
409409
// case AKEYCODE_NUMPAD_SUBTRACT:
410410
// event.key = SB_KEY_KP_MINUS;
411411
// break;
412-
case AKEYCODE_SLASH:
413-
event.key = SB_KEY_KP_DIV;
414-
break;
412+
// AKEYCODE_SLASH is '?'
413+
// case AKEYCODE_SLASH:
414+
// event.key = SB_KEY_KP_DIV;
415+
// break;
415416
case AKEYCODE_PAGE_UP:
416417
event.key = SB_KEY_PGUP;
417418
break;

src/platform/android/src/net/sourceforge/smallbasic/MainActivity.java

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
import android.content.DialogInterface;
3636
import android.content.Intent;
3737
import android.graphics.Rect;
38-
import android.media.AudioManager;
3938
import android.net.Uri;
4039
import android.os.Build;
4140
import android.os.Bundle;
@@ -54,13 +53,12 @@
5453
public class MainActivity extends NativeActivity {
5554
private static final String TAG = "smallbasic";
5655
private static final String WEB_BAS = "web.bas";
57-
private static final String SCHEME_BAS = "scheme.bas";
56+
private static final String SCHEME_BAS = "qrcode.bas";
5857
private static final String SCHEME = "smallbasic://x/";
5958
private String _startupBas = null;
6059
private boolean _untrusted = false;
6160
private ExecutorService _audioExecutor = Executors.newSingleThreadExecutor();
6261
private Queue<Sound> _sounds = new ConcurrentLinkedQueue<Sound>();
63-
private float _ringVolume;
6462

6563
static {
6664
System.loadLibrary("smallbasic");
@@ -130,9 +128,7 @@ public void onClick(DialogInterface dialog, int index) {
130128
}
131129

132130
public void playTone(int frq, int dur, int vol) {
133-
float volume = (vol / 100f) * _ringVolume;
134-
Log.i(TAG, "playTone: " + frq + " " + dur + " " + vol + " " + volume);
135-
131+
float volume = (vol / 100f);
136132
final Sound sound = new Sound(frq, dur, volume);
137133
_sounds.add(sound);
138134
_audioExecutor.execute(new Runnable() {
@@ -202,11 +198,6 @@ protected void onCreate(Bundle savedInstanceState) {
202198
} catch (Exception e) {
203199
Log.i(TAG, "Failed to start web service: ", e);
204200
}
205-
206-
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
207-
float ringVolume = audioManager.getStreamVolume(AudioManager.STREAM_RING);
208-
float maxRingVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_RING);
209-
_ringVolume = ringVolume / maxRingVolume;
210201
}
211202

212203
private String buildRunForm(String buffer, String token) {

web/qrcode/pom.xml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<!-- mvn clean compile assembly:single -->
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
<groupId>net.sourceforge.smallbasic</groupId>
7+
<artifactId>QrEncoder</artifactId>
8+
<version>1.0</version>
9+
<packaging>jar</packaging>
10+
<name>QrEncoder</name>
11+
<description>Encode a SmallBASIC program into a QRCode</description>
12+
<dependencies>
13+
<dependency>
14+
<groupId>com.google.zxing</groupId>
15+
<artifactId>core</artifactId>
16+
<version>2.0</version>
17+
</dependency>
18+
</dependencies>
19+
<build>
20+
<plugins>
21+
<plugin>
22+
<artifactId>maven-compiler-plugin</artifactId>
23+
<configuration>
24+
<source>1.7</source>
25+
<target>1.7</target>
26+
</configuration>
27+
</plugin>
28+
<plugin>
29+
<artifactId>maven-assembly-plugin</artifactId>
30+
<configuration>
31+
<archive>
32+
<manifest>
33+
<mainClass>net.sourceforge.smallbasic.QrEncoder</mainClass>
34+
</manifest>
35+
</archive>
36+
<descriptorRefs>
37+
<descriptorRef>jar-with-dependencies</descriptorRef>
38+
</descriptorRefs>
39+
</configuration>
40+
</plugin>
41+
</plugins>
42+
</build>
43+
</project>
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package net.sourceforge.smallbasic;
2+
3+
import java.awt.Color;
4+
import java.awt.Graphics2D;
5+
import java.awt.image.BufferedImage;
6+
import java.io.ByteArrayOutputStream;
7+
import java.io.DataInputStream;
8+
import java.io.DataOutputStream;
9+
import java.io.FileInputStream;
10+
import java.io.FileNotFoundException;
11+
import java.io.FileOutputStream;
12+
import java.io.IOException;
13+
import java.util.HashMap;
14+
import java.util.Map;
15+
import java.util.zip.GZIPOutputStream;
16+
17+
import javax.imageio.ImageIO;
18+
import javax.xml.bind.DatatypeConverter;
19+
20+
import com.google.zxing.BarcodeFormat;
21+
import com.google.zxing.EncodeHintType;
22+
import com.google.zxing.WriterException;
23+
import com.google.zxing.common.BitMatrix;
24+
import com.google.zxing.qrcode.QRCodeWriter;
25+
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
26+
27+
/**
28+
* Encode SmallBASIC program into a QrCode
29+
*
30+
* @author chrisws
31+
*/
32+
public class QrEncoder {
33+
/**
34+
* @param args
35+
* @throws IOException
36+
* @throws WriterException
37+
*/
38+
public static void main(String[] args) throws IOException, WriterException {
39+
new QrEncoder().process(args[0]);
40+
}
41+
42+
protected String cleanupCode(String fileText) {
43+
String result = fileText.replaceAll("(?mi)^\\s*?rem.*[\\r\\n]", "");
44+
result = result.replaceAll("(?mi)^\\s*?'.*[\\r\\n]", "");
45+
result = result.replaceAll("(?mi)^\\s*?#.*[\\r\\n]", "");
46+
return result.trim();
47+
}
48+
49+
/**
50+
* Creates a QR code image using the given text and dimensions
51+
*/
52+
protected byte[] createQRCode(String qrText, int size) throws WriterException, IOException {
53+
Map<EncodeHintType, Object> hintMap = new HashMap<EncodeHintType, Object>();
54+
hintMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
55+
QRCodeWriter qrCodeWriter = new QRCodeWriter();
56+
BitMatrix byteMatrix = qrCodeWriter.encode(qrText, BarcodeFormat.QR_CODE, size, size, hintMap);
57+
int crunchifyWidth = byteMatrix.getWidth();
58+
BufferedImage image = new BufferedImage(crunchifyWidth, crunchifyWidth, BufferedImage.TYPE_INT_RGB);
59+
image.createGraphics();
60+
Graphics2D graphics = (Graphics2D) image.getGraphics();
61+
graphics.setColor(Color.WHITE);
62+
graphics.fillRect(0, 0, crunchifyWidth, crunchifyWidth);
63+
graphics.setColor(Color.BLACK);
64+
for (int i = 0; i < crunchifyWidth; i++) {
65+
for (int j = 0; j < crunchifyWidth; j++) {
66+
if (byteMatrix.get(i, j)) {
67+
graphics.fillRect(i, j, 1, 1);
68+
}
69+
}
70+
}
71+
ByteArrayOutputStream output = new ByteArrayOutputStream();
72+
ImageIO.write(image, "png", output);
73+
return output.toByteArray();
74+
}
75+
76+
protected String getFileText(String fileName) throws IOException {
77+
ByteArrayOutputStream out = new ByteArrayOutputStream();
78+
try (DataInputStream is = new DataInputStream(new FileInputStream(fileName));) {
79+
byte[] buf = new byte[1024];
80+
int len = is.read(buf);
81+
while (len != -1) {
82+
out.write(buf, 0, len);
83+
len = is.read(buf);
84+
}
85+
}
86+
return out.toString("utf-8");
87+
}
88+
89+
protected void process(String fileName) throws IOException,
90+
FileNotFoundException, WriterException {
91+
92+
// load the file text
93+
String fileText = getFileText(fileName);
94+
95+
// remove comments and empty white space
96+
fileText = cleanupCode(fileText);
97+
98+
// gzip the result
99+
String zipText = zipBase64(fileText);
100+
101+
// encode the zipped data into a qrcode
102+
byte[] out = createQRCode(zipText, 512);
103+
104+
writeOutput(out, fileName + ".png");
105+
}
106+
107+
protected void writeOutput(byte[] bytes, String fileName) throws FileNotFoundException, IOException {
108+
try (DataOutputStream out = new DataOutputStream(new FileOutputStream(fileName));) {
109+
out.write(bytes, 0, bytes.length);
110+
}
111+
}
112+
113+
protected String zipBase64(String fileText) throws IOException {
114+
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
115+
DataOutputStream stream = new DataOutputStream(new GZIPOutputStream(buffer));
116+
stream.write(fileText.getBytes());
117+
stream.close();
118+
return DatatypeConverter.printBase64Binary(buffer.toByteArray());
119+
}
120+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package net.sourceforge.smallbasic;
2+
3+
import java.io.IOException;
4+
5+
import org.junit.Assert;
6+
import org.junit.Test;
7+
8+
/**
9+
* Tests for QrEncoder
10+
*
11+
* @author chrisws
12+
*/
13+
public class TestQrEncoder {
14+
@Test
15+
public void testCleanup() {
16+
QrEncoder inst = new QrEncoder();
17+
String fileText = " 'quote comments\r\n# hash comments\nREM remarks\r\n? 'hello'\n? 10";
18+
String expectedText = "? 'hello'\n? 10";
19+
String result = inst.cleanupCode(fileText);
20+
Assert.assertEquals(expectedText, result);
21+
}
22+
23+
@Test
24+
public void testZipBase64() throws IOException {
25+
QrEncoder inst = new QrEncoder();
26+
String fileText = "? 'hello'\n? 10";
27+
String expectedText = "H4sIAAAAAAAAALNXUM9IzcnJV+eyVzA0AAAgB4JODgAAAA==";
28+
String result = inst.zipBase64(fileText);
29+
Assert.assertEquals(expectedText, result);
30+
}
31+
32+
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)