diff --git a/app-android/app/src/main/AndroidManifest.xml b/app-android/app/src/main/AndroidManifest.xml
index 225ca27..a0a3b2c 100644
--- a/app-android/app/src/main/AndroidManifest.xml
+++ b/app-android/app/src/main/AndroidManifest.xml
@@ -8,6 +8,7 @@
+
diff --git a/app-android/app/src/main/java/at/bitfire/gfxtablet/CanvasActivity.java b/app-android/app/src/main/java/at/bitfire/gfxtablet/CanvasActivity.java
index e961564..22761d6 100644
--- a/app-android/app/src/main/java/at/bitfire/gfxtablet/CanvasActivity.java
+++ b/app-android/app/src/main/java/at/bitfire/gfxtablet/CanvasActivity.java
@@ -21,14 +21,18 @@ import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.Toast;
+import at.bitfire.gfxtablet.NetEvent.Type;
public class CanvasActivity extends AppCompatActivity implements View.OnSystemUiVisibilityChangeListener, SharedPreferences.OnSharedPreferenceChangeListener {
private static final int RESULT_LOAD_IMAGE = 1;
private static final String TAG = "GfxTablet.Canvas";
+ private static CanvasActivity instance;
+ public static CanvasActivity get() { return instance; }
final Uri homepageUri = Uri.parse(("https://gfxtablet.bitfire.at"));
NetworkClient netClient;
+ NetworkServer netServer;
SharedPreferences preferences;
boolean fullScreen = false;
@@ -37,6 +41,7 @@ public class CanvasActivity extends AppCompatActivity implements View.OnSystemUi
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ instance = this;
preferences = PreferenceManager.getDefaultSharedPreferences(this);
preferences.registerOnSharedPreferenceChangeListener(this);
@@ -46,6 +51,10 @@ public class CanvasActivity extends AppCompatActivity implements View.OnSystemUi
// create network client in a separate thread
netClient = new NetworkClient(PreferenceManager.getDefaultSharedPreferences(this));
new Thread(netClient).start();
+ // create network server in a separate thread
+ netServer = new NetworkServer(PreferenceManager.getDefaultSharedPreferences(this));
+ new Thread(netServer).start();
+
new ConfigureNetworkingTask().execute();
// notify CanvasView of the network client
@@ -77,6 +86,10 @@ public class CanvasActivity extends AppCompatActivity implements View.OnSystemUi
return true;
}
+ public void sendMotionStopSignal(){
+ netClient.getQueue().add(new NetEvent(Type.TYPE_MOTION, (short) 0, (short) 0, (short) 0));
+ }
+
@Override
public void onBackPressed() {
if (fullScreen)
@@ -166,7 +179,7 @@ public class CanvasActivity extends AppCompatActivity implements View.OnSystemUi
}
public void clearTemplateImage(MenuItem item) {
- preferences.edit().remove(SettingsActivity.KEY_TEMPLATE_IMAGE).commit();
+ preferences.edit().remove(SettingsActivity.KEY_TEMPLATE_IMAGE).apply();
showTemplateImage();
}
@@ -184,7 +197,7 @@ public class CanvasActivity extends AppCompatActivity implements View.OnSystemUi
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
- preferences.edit().putString(SettingsActivity.KEY_TEMPLATE_IMAGE, picturePath).commit();
+ preferences.edit().putString(SettingsActivity.KEY_TEMPLATE_IMAGE, picturePath).apply();
showTemplateImage();
} finally {
cursor.close();
@@ -192,6 +205,9 @@ public class CanvasActivity extends AppCompatActivity implements View.OnSystemUi
}
}
+ /**
+ * Fits chosen image to screen size.
+ */
public void showTemplateImage() {
ImageView template = (ImageView)findViewById(R.id.canvas_template);
template.setImageDrawable(null);
@@ -200,9 +216,8 @@ public class CanvasActivity extends AppCompatActivity implements View.OnSystemUi
String picturePath = preferences.getString(SettingsActivity.KEY_TEMPLATE_IMAGE, null);
if (picturePath != null)
try {
- // TODO load bitmap efficiently, for intended view size and display resolution
- // https://developer.android.com/training/displaying-bitmaps/load-bitmap.html
final Drawable drawable = new BitmapDrawable(getResources(), picturePath);
+ template.setScaleType(ImageView.ScaleType.FIT_XY);
template.setImageDrawable(drawable);
} catch (Exception e) {
Toast.makeText(this, e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
diff --git a/app-android/app/src/main/java/at/bitfire/gfxtablet/CanvasView.java b/app-android/app/src/main/java/at/bitfire/gfxtablet/CanvasView.java
index 8cc27bb..fffd108 100644
--- a/app-android/app/src/main/java/at/bitfire/gfxtablet/CanvasView.java
+++ b/app-android/app/src/main/java/at/bitfire/gfxtablet/CanvasView.java
@@ -56,8 +56,8 @@ public class CanvasView extends View implements SharedPreferences.OnSharedPrefer
protected void setBackground() {
if (settings.getBoolean(SettingsActivity.KEY_DARK_CANVAS, false))
setBackgroundColor(Color.BLACK);
- else
- setBackgroundResource(R.drawable.bg_grid_pattern);
+ //else
+ //setBackgroundResource(R.drawable.bg_grid_pattern); //<-- Add this as option?
}
protected void setInputMethods() {
diff --git a/app-android/app/src/main/java/at/bitfire/gfxtablet/NetworkClient.java b/app-android/app/src/main/java/at/bitfire/gfxtablet/NetworkClient.java
index c437725..32a6264 100644
--- a/app-android/app/src/main/java/at/bitfire/gfxtablet/NetworkClient.java
+++ b/app-android/app/src/main/java/at/bitfire/gfxtablet/NetworkClient.java
@@ -54,7 +54,7 @@ public class NetworkClient implements Runnable {
byte[] data = event.toByteArray();
DatagramPacket pkt = new DatagramPacket(data, data.length, destAddress, GFXTABLET_PORT);
socket.send(pkt);
- }
+ }
} catch (Exception e) {
Log.e("GfxTablet", "motionQueue failed: " + e.getMessage());
}
diff --git a/app-android/app/src/main/java/at/bitfire/gfxtablet/NetworkServer.java b/app-android/app/src/main/java/at/bitfire/gfxtablet/NetworkServer.java
new file mode 100644
index 0000000..0f3a44b
--- /dev/null
+++ b/app-android/app/src/main/java/at/bitfire/gfxtablet/NetworkServer.java
@@ -0,0 +1,89 @@
+package at.bitfire.gfxtablet;
+
+import android.content.SharedPreferences;
+import android.util.Log;
+import android.util.SparseArray;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.io.FileOutputStream;
+
+public class NetworkServer implements Runnable {
+ static final int GFXTABLET_PORT = 40118;
+ NetworkClient netClient;
+ final SharedPreferences preferences;
+
+ NetworkServer(SharedPreferences preferences) {
+ this.preferences = preferences;
+ }
+
+ @Override
+ public void run() {
+ try {
+ DatagramSocket socket = new DatagramSocket(GFXTABLET_PORT);
+
+ SparseArray buffer = new SparseArray<>();
+ // Init has to be done twice because the first call will be set on the server with 0.0.0.0
+ // but we nee the ip of the client.
+ CanvasActivity.get().sendMotionStopSignal();
+ CanvasActivity.get().sendMotionStopSignal();
+ while (true) {
+ byte[] buf = new byte[60030];
+ DatagramPacket packet = new DatagramPacket(buf, buf.length);
+ socket.receive(packet);
+ int n = buf[60029];
+ Log.i("receive:", String.valueOf(n));
+ if (n != 0){
+ buffer.put(n, buf);
+ } else if (buffer.size() > 0 ) {
+ try {
+ String path = CanvasActivity.get().getFilesDir().getPath() + "/desktop.png";
+ path = "/storage/emulated/0/test.png"; //TODO set via options
+ Log.i("buffer:", String.valueOf(buf[0]));
+ boolean parts = buffer.size() == (int) buf[0];
+ for (int i=0; i < buf[0]; i++) {
+ if (parts) {
+ Log.i("keyAt " + i, String.valueOf(buffer.keyAt(i)));
+ parts = buffer.keyAt(i) == i+1;
+ }
+ }
+ if (!parts) {
+ buffer.clear();
+ CanvasActivity.get().sendMotionStopSignal();
+ Log.i("Image Problem", "tying to refetch the screenshot");
+ continue;
+ }
+ Log.i("receive", "completed with " + buffer.size());
+
+ FileOutputStream fos = new FileOutputStream(path);
+ for (int i=1; i <= buffer.size(); i++) {
+ fos.write(buffer.get(i), 0, 60000);
+ }
+ fos.flush();
+ fos.close();
+ File file = new File(path);
+ long size = file.length();
+ Log.i("file-path", path);
+ Log.i("file-size", String.valueOf(size));
+ Log.i("file-path-current", preferences.getString(SettingsActivity.KEY_TEMPLATE_IMAGE, null));
+ preferences.edit().putString(SettingsActivity.KEY_TEMPLATE_IMAGE, path).apply();
+ CanvasActivity.get().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ CanvasActivity.get().showTemplateImage();
+ }
+ });
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ //compile image and set it
+ buffer.clear();
+ }
+ }
+ } catch (Exception e) {
+ Log.i("GfxTablet", "Screenshot server failed: " + e.getMessage());
+ }
+ }
+}
diff --git a/app-android/build.gradle b/app-android/build.gradle
index 0209e1e..8874234 100644
--- a/app-android/build.gradle
+++ b/app-android/build.gradle
@@ -4,7 +4,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:1.2.3'
+ classpath 'com.android.tools.build:gradle:2.2.3'
}
}
allprojects {
diff --git a/app-android/gradle/wrapper/gradle-wrapper.properties b/app-android/gradle/wrapper/gradle-wrapper.properties
index 0c71e76..74ef61c 100644
--- a/app-android/gradle/wrapper/gradle-wrapper.properties
+++ b/app-android/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Wed Apr 10 15:27:10 PDT 2013
+#Tue Feb 21 12:16:03 CET 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
diff --git a/driver-uinput/networktablet.c b/driver-uinput/networktablet.c
index 93cab80..5a51bc1 100644
--- a/driver-uinput/networktablet.c
+++ b/driver-uinput/networktablet.c
@@ -1,4 +1,10 @@
+#include
+#include
+#include
+#include
+#include
+#include
#include
#include
#include
@@ -19,7 +25,15 @@
}
-int udp_socket;
+int udp_socket, sending;
+
+typedef struct event_packet event_packet;
+typedef struct sockaddr_in sockaddr_in;
+
+typedef struct sending_t {
+ sockaddr_in from;
+ int slen;
+} sending_t;
void init_device(int fd)
@@ -74,12 +88,12 @@ void init_device(int fd)
int prepare_socket()
{
int s;
- struct sockaddr_in addr;
+ sockaddr_in addr;
if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
die("error: prepare_socket()");
- bzero(&addr, sizeof(struct sockaddr_in));
+ bzero(&addr, sizeof(sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(GFXTABLET_PORT);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
@@ -104,11 +118,74 @@ void quit(int signal) {
close(udp_socket);
}
+void msleep(int ms){
+ struct timespec req = {0};
+ req.tv_sec = 0;
+ req.tv_nsec = ms * 1000000L;
+ nanosleep(&req, (struct timespec *)NULL);
+}
-int main(void)
-{
+void *send_current_screen(void *arg){
+ sending_t *args = (sending_t*) arg;
+ sockaddr_in from = args->from;
+ int slen = args->slen;
+ Display *disp = XOpenDisplay(":0");
+
+ if (sending || !disp) {
+ return NULL;
+ }
+ printf("\nsend_thread\n");
+
+ msleep(300);
+ sending=1;
+ Window root;
+ cairo_surface_t *surface;
+ int scr;
+ scr = DefaultScreen(disp);
+ root = DefaultRootWindow(disp);
+ /* get the root surface on given display */
+ surface = cairo_xlib_surface_create(disp, root, DefaultVisual(disp, scr),
+ DisplayWidth(disp, scr),
+ DisplayHeight(disp, scr));
+ /* right now, the tool only outputs PNG images */
+ cairo_surface_write_to_png( surface, "test.png" );
+ /* free the memory*/
+ cairo_surface_destroy(surface);
+
+ FILE *istream;
+ if ( (istream = fopen("test.png", "r" ) ) == NULL ){
+ die("file non-existant!");
+ }
+ from.sin_port = htons(GFXTABLET_PORT);
+ int max=60000;
+ char buff[max+30];
+ int n=1;
+ while(fread(buff,sizeof(char),max,istream) != 0){
+ printf("Send packet to %s:%d\n", inet_ntoa(from.sin_addr), ntohs(from.sin_port));
+ buff[max +29] = n;
+ if (sendto(udp_socket, buff, sizeof(buff), 0, (struct sockaddr*) &from, slen) == -1){
+ die("sendto()");
+ }
+ n++;
+ for (int r = 0; r <= max ; r++){
+ buff[r] = 0;
+ }
+ }
+ fclose (istream );
+ char buf[1];
+ buf[0] = n-1;
+ if (sendto(udp_socket, buf, strlen(buff)+1, 0, (struct sockaddr*) &from, slen) == -1){
+ die("sendto()");
+ }
+ sending=0;
+}
+
+int main(void){
int device;
- struct event_packet ev_pkt;
+ sending=0;
+ event_packet ev_pkt;
+ sending_t sock_t;
+ pthread_t ev_retreive_t, screen_send_t;
if ((device = open("/dev/uinput", O_WRONLY | O_NONBLOCK)) < 0)
die("error: open");
@@ -122,7 +199,7 @@ int main(void)
signal(SIGINT, quit);
signal(SIGTERM, quit);
- while (recv(udp_socket, &ev_pkt, sizeof(ev_pkt), 0) >= 9) { // every packet has at least 9 bytes
+ while (recvfrom(udp_socket, &ev_pkt, sizeof(event_packet), 0, (struct sockaddr *) &sock_t.from, &sock_t.slen) >= 9) { // every packet has at least 9 bytes
printf("."); fflush(0);
if (memcmp(ev_pkt.signature, "GfxTablet", 9) != 0) {
@@ -165,7 +242,13 @@ int main(void)
printf("sent button: %hhi, %hhu\n", ev_pkt.button, ev_pkt.down);
send_event(device, EV_SYN, SYN_REPORT, 1);
break;
+ }
+ if (ev_pkt.pressure == 0 && memcmp(inet_ntoa(sock_t.from.sin_addr), "0.0.0.0", 7) != 0) {
+ if(pthread_create(&screen_send_t, NULL, send_current_screen, &sock_t)) {
+ fprintf(stderr, "Error creating thread\n");
+ return 1;
+ }
}
}
close(udp_socket);