changeset 27:807f7e4eaebe

starting update to latest toolchain
author Carl Byington <carl@five-ten-sg.com>
date Thu, 08 Nov 2018 11:39:13 -0800
parents 3a5df66c0480
children a5f1c68e4519
files .classpath .project AndroidManifest.xml Makefile ant.properties app/build.gradle app/src/main/AndroidManifest.xml app/src/main/java/com/five_ten_sg/connectbot/monitor/MonitorActivity.java app/src/main/java/com/five_ten_sg/connectbot/monitor/MonitorService.java app/src/main/res/drawable-hdpi/icon.png app/src/main/res/drawable-hdpi/notification_icon.png app/src/main/res/drawable-ldpi/icon.png app/src/main/res/drawable-ldpi/notification_icon.png app/src/main/res/drawable-mdpi/icon.png app/src/main/res/drawable-mdpi/notification_icon.png app/src/main/res/drawable-xhdpi/icon.png app/src/main/res/drawable-xhdpi/notification_icon.png app/src/main/res/drawable-xxhdpi/icon.png app/src/main/res/drawable-xxhdpi/notification_icon.png app/src/main/res/drawable-xxxhdpi/icon.png app/src/main/res/drawable-xxxhdpi/notification_icon.png app/src/main/res/layout/main.xml app/src/main/res/menu/main.xml app/src/main/res/values-sw600dp/dimens.xml app/src/main/res/values-sw720dp-land/dimens.xml app/src/main/res/values-v11/styles.xml app/src/main/res/values-v14/styles.xml app/src/main/res/values/dimens.xml app/src/main/res/values/strings.xml app/src/main/res/values/styles.xml build.xml proguard-project.txt project.properties res/drawable-hdpi/icon.png res/drawable-hdpi/notification_icon.png res/drawable-ldpi/icon.png res/drawable-ldpi/notification_icon.png res/drawable-mdpi/icon.png res/drawable-mdpi/notification_icon.png res/drawable-xhdpi/icon.png res/drawable-xhdpi/notification_icon.png res/drawable-xxhdpi/icon.png res/drawable-xxhdpi/notification_icon.png res/drawable-xxxhdpi/icon.png res/drawable-xxxhdpi/notification_icon.png res/layout/main.xml res/menu/main.xml res/values-sw600dp/dimens.xml res/values-sw720dp-land/dimens.xml res/values-v11/styles.xml res/values-v14/styles.xml res/values/dimens.xml res/values/strings.xml res/values/styles.xml src/com/five_ten_sg/connectbot/monitor/MonitorActivity.java src/com/five_ten_sg/connectbot/monitor/MonitorService.java
diffstat 56 files changed, 947 insertions(+), 957 deletions(-) [+]
line wrap: on
line diff
--- a/.classpath	Fri May 01 12:34:17 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
-	<classpathentry kind="src" path="src"/>
-	<classpathentry kind="src" path="gen"/>
-	<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
-	<classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
-	<classpathentry kind="output" path="bin/classes"/>
-</classpath>
--- a/.project	Fri May 01 12:34:17 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-	<name>510ConnectbotMonitor</name>
-	<comment></comment>
-	<projects>
-	</projects>
-	<buildSpec>
-		<buildCommand>
-			<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
-			<arguments>
-			</arguments>
-		</buildCommand>
-		<buildCommand>
-			<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
-			<arguments>
-			</arguments>
-		</buildCommand>
-		<buildCommand>
-			<name>org.eclipse.jdt.core.javabuilder</name>
-			<arguments>
-			</arguments>
-		</buildCommand>
-		<buildCommand>
-			<name>com.android.ide.eclipse.adt.ApkBuilder</name>
-			<arguments>
-			</arguments>
-		</buildCommand>
-	</buildSpec>
-	<natures>
-		<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
-		<nature>org.eclipse.jdt.core.javanature</nature>
-	</natures>
-</projectDescription>
--- a/AndroidManifest.xml	Fri May 01 12:34:17 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.five_ten_sg.connectbot.monitor"
-    android:versionCode="1"
-    android:versionName="1.0.4-0" >
-
-    <uses-sdk
-        android:minSdkVersion="8"
-        android:targetSdkVersion="17" />
-
-    <uses-permission android:name="android.permission.INTERNET" />
-    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-    <uses-permission android:name="android.permission.WAKE_LOCK" />
-
-    <application
-        android:debuggable="true"
-        android:allowBackup="false"
-        android:icon="@drawable/icon"
-        android:label="@string/app_name"
-        android:theme="@style/AppTheme" >
-        <activity
-            android:name="com.five_ten_sg.connectbot.monitor.MonitorActivity"
-            android:label="@string/app_name" >
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-
-        <service
-            android:name="com.five_ten_sg.connectbot.monitor.MonitorService"
-            android:description="@string/service_desc" >
-            <intent-filter>
-                <action android:name="com.five_ten_sg.connectbot.monitor.MonitorService" />
-            </intent-filter>
-        </service>
-    </application>
-
-</manifest>
--- a/Makefile	Fri May 01 12:34:17 2015 -0700
+++ b/Makefile	Thu Nov 08 11:39:13 2018 -0800
@@ -1,13 +1,22 @@
 #mc40 is "On Device Storage"
 #tc55 is "Internal Storage"
 
-style=release
-dest=/run/user/1000/gvfs/mtp*/*torage/Download
-apk='bin/510ConnectbotMonitor-$(style).apk'
+style:=release
+dest:=/run/user/1000/gvfs/mtp*/*torage/Download
+ver:=$(shell grep versionName app/src/main/AndroidManifest.xml | cut -d'"' -f2)
+apk:='app/build/outputs/apk/510ConnectbotMonitor-$(ver).apk'
+id:=$(shell hg id --id || echo 1)
+da:=$(shell date +%Y-%m-%d)
+version:=\
+<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\
+<resources>\n\
+	<string name=\"msg_version\" translatable=\"false\">510ConnectbotMonitor $(ver) ($(id) $(da))</string>\n\
+</resources>\n
+
 ifeq ($(style),release)
-    debuggable=false
+    task:=assembleArmRelease
 else
-	debuggable=true
+	task:=assembleArmDebug
 endif
 
 all:
@@ -15,10 +24,15 @@
 	make builder
 
 builder:
-	sed -i -e 's/android:debuggable=".*"/android:debuggable="$(debuggable)"/g' AndroidManifest.xml
-	rm -rf gen bin
-	android update project -p . -t android-16
-	ant $(style)
+	rm -rf app/build/*
+	echo -e "$(version)" >app/src/main/res/values/version.xml
+	cat app/src/main/res/values/version.xml
+	ANDROID_HOME=/home/carl/Android/Sdk ANDROID_NDK_HOME=/home/carl/Android/Sdk/ndk-bundle ./gradlew $(task)
+	mv app/build/outputs/apk/arm/$(style)/app-arm-$(style).apk $(apk)
+	ls -al app/build/outputs/apk
+
+docs:
+	(cd xml; make)
 
 install:
 	cp $(apk) $(dest)
--- a/ant.properties	Fri May 01 12:34:17 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-# This file is used to override default values used by the Ant build system.
-#
-# This file must be checked in Version Control Systems, as it is
-# integral to the build system of your project.
-
-# This file is only used by the Ant script.
-
-# You can use this to override default values such as
-#  'source.dir' for the location of your java source folder and
-#  'out.dir' for the location of your output folder.
-
-# You can also use it define how the release builds are signed by declaring
-# the following properties:
-#  'key.store' for the location of your keystore and
-#  'key.alias' for the name of the key to use.
-# The password will be asked during the build when you use the 'release' target.
-
-source.dir=src
-out.dir=bin
-key.store=510Connectbot.keystore
-key.alias=510Connectbot
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/build.gradle	Thu Nov 08 11:39:13 2018 -0800
@@ -0,0 +1,89 @@
+task copyDebugLibTask(type: Copy) {
+    from 'build/intermediates/binaries/debug/arm/lib/armeabi'
+    into 'src/main/jniLibs/armeabi'
+}
+task copyReleaseLibTask(type: Copy) {
+    from 'build/intermediates/binaries/release/arm/lib/armeabi'
+    into 'src/main/jniLibs/armeabi'
+}
+
+tasks.whenTaskAdded { task ->
+    if (task.name.contains("merge") && task.name.contains("JniLibFolders")) {
+        if (task.name.contains("ArmDebug")) {
+            task.dependsOn copyDebugLibTask
+        }
+        if (task.name.contains("ArmRelease")) {
+            task.dependsOn copyReleaseLibTask
+        }
+    }
+}
+
+
+apply plugin: 'com.android.application'
+
+android {
+    signingConfigs {
+        release {
+            print "\nNo Console\n"
+            def read = System.in.newReader().&readLine
+            print "\nkey store password"
+            storePassword = read()
+            print "\nkey alias password"
+            keyPassword   = read()
+            print "\nDone\n"
+            storeFile = file("../510Connectbot.keystore")
+            storeType = "jks"
+            keyAlias  = "510Connectbot"
+        }
+    }
+    compileSdkVersion = 16
+    buildTypes {
+        release {
+            minifyEnabled = false
+            signingConfig = signingConfigs.release
+            ndk {
+                debuggable = false
+                abiFilters 'armeabi-v7a'
+            }
+        }
+        debug {
+            debuggable = true
+            ndk {
+                debuggable = true
+                abiFilters 'armeabi-v7a'
+            }
+        }
+    }
+    flavorDimensions "arch"
+    productFlavors {
+        arm {
+            dimension "arch"
+        }
+        x86 {
+            dimension "arch"
+        }
+    }
+    sourceSets {
+        main {
+            jni {
+                srcDir "Exec"
+            }
+        }
+    }
+
+    defaultConfig {
+        applicationId = "com.five_ten_sg.connectbot"
+        minSdkVersion = 8
+        targetSdkVersion = 15
+        ndk {
+            moduleName = "com_google_ase_Exec"
+        }
+    }
+
+    externalNativeBuild {
+        ndkBuild {
+            path "src/main/jni/Android.mk"
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/src/main/AndroidManifest.xml	Thu Nov 08 11:39:13 2018 -0800
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.five_ten_sg.connectbot.monitor"
+    android:versionCode="1"
+    android:versionName="1.0.4-0" >
+
+    <uses-sdk
+        android:minSdkVersion="8"
+        android:targetSdkVersion="17" />
+
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+    <application
+        android:debuggable="true"
+        android:allowBackup="false"
+        android:icon="@drawable/icon"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:name="com.five_ten_sg.connectbot.monitor.MonitorActivity"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <service
+            android:name="com.five_ten_sg.connectbot.monitor.MonitorService"
+            android:description="@string/service_desc" >
+            <intent-filter>
+                <action android:name="com.five_ten_sg.connectbot.monitor.MonitorService" />
+            </intent-filter>
+        </service>
+    </application>
+
+</manifest>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/src/main/java/com/five_ten_sg/connectbot/monitor/MonitorActivity.java	Thu Nov 08 11:39:13 2018 -0800
@@ -0,0 +1,106 @@
+package com.five_ten_sg.connectbot.monitor;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.net.wifi.WifiManager.WifiLock;
+import android.net.wifi.WifiManager;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.PowerManager;
+import android.util.Log;
+import android.widget.TextView;
+
+public class MonitorActivity extends Activity {
+    public final static String TAG = "ConnectBot.MonitorActivity";
+
+    public static final int MESSAGE_CODE_PRINT = 6000;
+    private final int       LINES = 20;
+    private String[]        texts   = new String[LINES];
+    private int             start   = 0;
+    private int             count   = 0;
+    private TextView        text    = null;
+    private MonitorService  bound   = null;
+    private Handler         handler = new Handler() {
+        @Override
+        public void handleMessage (Message msg) {
+            if (msg.what == MESSAGE_CODE_PRINT) {
+                printer((String)msg.obj);
+            } else {
+                super.handleMessage(msg);
+            }
+        }
+    };
+    private ServiceConnection connection = new ServiceConnection() {
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            Log.i(TAG, "onServiceConnected()");
+            bound = ((MonitorService.MonitorBinder)service).getService();
+            bound.handler = handler;
+        }
+        public void onServiceDisconnected(ComponentName className) {
+            Log.i(TAG, "onServiceDisconnected()");
+            bound = null;
+        }
+    };
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main);
+        text = (TextView) findViewById(R.id.text2);
+        printer(getString(R.string.copyright));
+        String external_dir = Environment.getExternalStorageDirectory().getAbsolutePath();
+        printer("");
+        printer(String.format("External directory is %s", external_dir));
+        printer("");
+        Log.i(TAG, "binding to monitor service");
+        Intent intent = new Intent ("com.five_ten_sg.connectbot.monitor.MonitorService");
+        bindService(intent, connection, Context.BIND_AUTO_CREATE);
+    }
+
+    private void printer(String msg) {
+        if (count < LINES) count++;
+        else               start = (start+1) % LINES;
+        texts[(start+count-1) % LINES] = msg + "\n";
+        String c = "";
+        for (int i=0; i<count; i++) c = c.concat(texts[(start+i) % LINES]);
+        text.setText(c);
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        Log.i(TAG, "activity onStart()");
+    }
+
+    @Override
+    protected void onRestart() {
+        super.onRestart();
+        Log.i(TAG, "activity onRestart()");
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        Log.i(TAG, "activity onStop()");
+    }
+
+    @Override
+    protected void onDestroy() {
+        Log.i(TAG, "activity onDestroy()");
+        unbindService(connection);
+        super.onDestroy();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/src/main/java/com/five_ten_sg/connectbot/monitor/MonitorService.java	Thu Nov 08 11:39:13 2018 -0800
@@ -0,0 +1,593 @@
+package com.five_ten_sg.connectbot.monitor;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.HashMap;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.Locale;
+
+import android.app.Activity;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.net.wifi.WifiManager.WifiLock;
+import android.net.wifi.WifiManager;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.PowerManager;
+import android.speech.tts.TextToSpeech;
+import android.speech.tts.TextToSpeech.OnInitListener;
+import android.util.Log;
+import android.widget.TextView;
+
+public class MonitorService extends Service implements OnInitListener {
+    public final static String TAG = "ConnectBot.MonitorService";
+
+    public  static final char MONITOR_CMD_INIT          = 0;
+    public  static final char MONITOR_CMD_ACTIVATE      = 1;
+    public  static final char MONITOR_CMD_KEYSTATE      = 2;
+    public  static final char MONITOR_CMD_CURSORMOVE    = 3;
+    public  static final char MONITOR_CMD_SCREENCHANGE  = 4;
+    public  static final char MONITOR_CMD_FIELDVALUE    = 5;
+    public  static final char MONITOR_CMD_SETFIELD      = 5;
+    public  static final char MONITOR_CMD_GETFIELD      = 6;
+    public  static final char MONITOR_CMD_SCREENWATCH   = 7;
+    public  static final char MONITOR_CMD_DEPRESS       = 8;
+    public  static final char MONITOR_CMD_SHOWURL       = 9;
+    public  static final char MONITOR_CMD_SWITCHSESSION = 10;
+    public  static final char MONITOR_CMD_CURSORREQUEST = 11;
+
+    public  static final char CURSOR_REQUESTED      = 0;
+    public  static final char CURSOR_SCREEN_CHANGE  = 1;
+    public  static final char CURSOR_USER_KEY       = 2;
+
+    public static final int       MONITORPORT = 6000;
+    public static ConcurrentHashMap<Integer,CommunicationThread> clients = new ConcurrentHashMap<Integer,CommunicationThread>();
+    public static int             currentConnection = -1;
+
+    private boolean               speech  = false;
+    private TextToSpeech          talker  = null;
+    private BlockingQueue<String> talkerQueue = null;
+    public  Handler               handler = null;
+    private ServerSocket          serverSocket;
+    private Thread                serverThread = null;
+    private WifiManager.WifiLock  wifiLock;
+    private PowerManager.WakeLock wakeLock;
+    final private IBinder         binder = new MonitorBinder();
+
+
+    public class MonitorBinder extends Binder {
+        public MonitorService getService() {
+            return MonitorService.this;
+        }
+    }
+
+    @Override
+    public void onInit(int status) {
+        if (status == TextToSpeech.SUCCESS) {
+            talker.setLanguage(Locale.US);
+            speech = true;
+        }
+    }
+
+    @Override
+    public void onCreate() {
+        WifiManager wMgr = (WifiManager) getSystemService(Context.WIFI_SERVICE);
+        wifiLock = wMgr.createWifiLock(WifiManager.WIFI_MODE_FULL, "MyWifiLock");
+        wifiLock.acquire();
+
+        PowerManager pMgr = (PowerManager) getSystemService(Context.POWER_SERVICE);
+        wakeLock = pMgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
+        wakeLock.acquire();
+
+        talker = new TextToSpeech(this, this);
+        this.serverThread = new Thread(new ServerThread());
+        this.serverThread.start();
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        startService(new Intent(this, MonitorService.class));
+        return binder;
+    }
+
+    public void printer(String msg) {
+        if (handler != null) handler.sendMessage(handler.obtainMessage(MonitorActivity.MESSAGE_CODE_PRINT, msg));
+    }
+
+    public synchronized void setCurrentConnection(int connection) {
+        currentConnection = connection;
+    }
+
+    public synchronized int nextConnection() {
+        int c = 1;
+        while (clients.get(c) != null) c++;
+        return c;
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        Log.i(TAG, "service onStartCommand()");
+        return START_STICKY;
+    }
+
+    @Override
+    public void onDestroy() {
+        try {
+            Log.i(TAG, "service onDestroy()");
+            teCloseAll();
+            talker.stop();
+            talker.shutdown();
+            wifiLock.release();
+            wakeLock.release();
+            serverSocket.close();
+        } catch (IOException e) {
+            Log.e(TAG, "exception in onDestroy()", e);
+        }
+        super.onDestroy();
+    }
+
+    class ServerThread extends Thread {
+        public void run() {
+            Socket  socket = null;
+            int connection = 0;
+            try {
+                serverSocket = new ServerSocket(MONITORPORT);
+            } catch (IOException e) {
+                Log.e(TAG, "exception in ServerThread.run(), cannot create listening socket", e);
+                return;
+            }
+            while (true) {
+                try{
+                   socket     = serverSocket.accept();
+                   connection = nextConnection();
+                   CommunicationThread commThread = new CommunicationThread(connection, socket);
+                   clients.put(connection, commThread);
+                   commThread.start();
+                } catch (IOException e) {
+                   Log.e(TAG, "exception in ServerThread.run(), listening socket closed", e);
+                   break;
+                }
+            }
+        }
+    }
+
+    class triple {
+        private int l, c;
+        private char[] b;
+        public triple(int l, int c, char[] b) {
+            this.l = l;
+            this.c = c;
+            this.b = b;
+        }
+    }
+
+    class CommunicationThread extends Thread {
+        public  int            thread_id;
+        public  int            connection;
+        private String         initString = null;
+        private Socket         client_socket;
+        private InputStream    client_in;
+        private OutputStream   client_out;
+        private boolean        is_closing = false;
+        private Integer        getfields_outstanding = 0;
+        private BlockingQueue<triple>  value_queue = new ArrayBlockingQueue<triple>(1);
+        private BlockingQueue<char[]>  packet_queue = new ArrayBlockingQueue<char[]>(10000);
+
+        public CommunicationThread(int handle, Socket socket) {
+            connection    = handle;
+            client_socket = socket;
+            try {
+                client_in  = client_socket.getInputStream();
+                client_out = client_socket.getOutputStream();
+            } catch (IOException e) {
+                Log.e(TAG, "exception in CommunicationThread() constructor, cannot get socket streams", e);
+            }
+        }
+
+        public synchronized void abandon() {
+            value_queue.offer(new triple(0, 0, new char[0]));
+        }
+
+        public void speak(byte [] msg, boolean flush, boolean synchronous) {
+            if (speech) {
+                String smsg = bytesToString(msg);
+                if (synchronous) {
+                    HashMap<String, String> myHashParms = new HashMap();
+                    myHashParms.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, String.format("connection %d", connection));
+                	talker.speak(smsg, (flush) ? TextToSpeech.QUEUE_FLUSH : TextToSpeech.QUEUE_ADD, myHashParms);
+                    try {
+                        String x = talkerQueue.take(); // wait for completion
+                    } catch (InterruptedException e) {
+                        Log.e(TAG, "exception in cm.speak()", e);
+                    }
+                }
+                else {
+            	    talker.speak(smsg, (flush) ? TextToSpeech.QUEUE_FLUSH : TextToSpeech.QUEUE_ADD, null);
+                }
+            }
+        }
+
+        public String bytesToString(byte[] b) {
+            char[] c = new char[b.length];
+            int bp = 0;
+            for(int i = 0; i < c.length; i++) {
+                byte b1 = 0;
+                byte b2 = b[bp++];
+                c[i] = (char) (((b1 & 0x00FF) << 8) + (b2 & 0x00FF));
+            }
+            return new String(c);
+        }
+
+        public char[] bytesToChars(byte[] b, int len) {
+            char[] c = new char[len >> 1];
+            int bp = 0;
+            for(int i = 0; i < c.length; i++) {
+                byte b1 = b[bp++];
+                byte b2 = b[bp++];
+                c[i] = (char) (((b1 & 0x00FF) << 8) + (b2 & 0x00FF));
+            }
+            return c;
+        }
+
+        public byte[] charsToBytes(char[] c) {
+            byte[] b = new byte[c.length << 1];
+            int bp = 0;
+            for (int i=0; i<c.length; i++) {
+                b[bp++] = (byte) ((c[i] & 0xff00) >> 8);
+                b[bp++] = (byte)  (c[i] & 0x00ff);
+            }
+            return b;
+        }
+
+        void cleanup(char[] buf) {
+            int i;
+            for (i=0; i<buf.length; i++) {
+                if ((int)(buf[i]) < 32) buf[i] = ' ';
+            }
+        }
+
+        public int cmGetField(char[] c) {
+            int request;
+            synchronized(getfields_outstanding) {
+                request = getfields_outstanding;
+                getfields_outstanding = getfields_outstanding + 1;
+                value_queue.clear();  // we never have more than one outstanding getfield request from the reco thread on the connection
+                clientWrite(MONITOR_CMD_GETFIELD, c);
+            }
+            return request;
+        }
+
+        public synchronized void clientWrite(char cmd, char[] c) {
+            try {
+                if (client_out != null) {
+                    c[0] = (char)(c.length - 1);    // number of chars following
+                    c[1] = cmd;
+                    Log.i(TAG, String.format("sending %d command", (int)cmd));
+                    client_out.write(charsToBytes(c));
+                    client_out.flush();
+                }
+            }
+            catch (IOException e) {
+                Log.e(TAG, "exception in monitorWrite()", e);
+                try {
+                    client_out.close();
+                }
+                catch (IOException ee) {
+                    Log.e(TAG, "exception in monitorWrite() closing socket", ee);
+                }
+                client_out = null;
+            }
+        };
+
+        private char[] forceRead(int len) throws IOException {
+            int len2 = len*2;
+            int off  = 0;
+            byte[] b = new byte[len2];
+            while (off < len2) {
+                int l = client_in.read(b, off, len2-off);
+                if (l < 0) {
+                    is_closing = true;
+                    throw new IOException("eof");
+                }
+                off += l;
+            }
+            return bytesToChars(b, len2);
+        }
+
+        public char[] readPacket() throws IOException {
+            char[] len = forceRead(1);
+            return forceRead(len[0]);
+        }
+
+        public char[] nextPacket() throws IOException, InterruptedException {
+            char[] packet = packet_queue.poll();
+            if (packet == null) {
+                packet = readPacket();
+                if (packet[0] == MONITOR_CMD_FIELDVALUE) {
+                    synchronized(getfields_outstanding) {
+                        getfields_outstanding = getfields_outstanding - 1;
+                    }
+                }
+            }
+            return packet;
+        }
+
+        private triple reformatValue(char[] packet) {
+            int plen = packet.length;
+            char[] buf = new char[plen-3];
+            System.arraycopy(packet, 3, buf, 0, plen-3);
+            cleanup(buf);
+            Log.i(TAG, String.format("teFieldValue %d line %d column %d b.len %d", connection, (int)packet[1], (int)packet[2], buf.length));
+            return new triple(packet[1], packet[2], buf);
+        }
+
+        public triple peekValue(int request) {
+            try {
+                while (true) {
+                    char[] packet = readPacket();
+                    if (packet[0] == MONITOR_CMD_FIELDVALUE) {
+                        synchronized(getfields_outstanding) {
+                            getfields_outstanding = getfields_outstanding - 1;
+                            if (request == 0) {
+                                return reformatValue(packet);
+                            }
+                            else {
+                                packet_queue.put(packet);
+                                request = request - 1;
+                            }
+                        }
+                    }
+                    else {
+                        packet_queue.put(packet);
+                    }
+                }
+            } catch (IOException e) {
+                return new triple(0, 0, new char[0]);
+            } catch (InterruptedException e) {
+                return new triple(0, 0, new char[0]);
+            }
+        }
+
+        public void run() {
+            thread_id = android.os.Process.myTid();
+            Log.i(TAG, String.format("CommunicationThread.run() client %d connected", connection));
+            while (true) {
+                try {
+                    char[] packet = nextPacket();
+                    char[] buf;
+                    char cmd = packet[0];
+                    int plen = packet.length;
+                    //Log.i(TAG, String.format("received %d command length %d", (int)cmd, plen));
+                    switch (cmd) {
+                        case MONITOR_CMD_INIT:
+                            buf = new char[plen-1];
+                            System.arraycopy(packet, 1, buf, 0, plen-1);
+                            abandonGetField(connection);
+                            initString = new String(buf);
+                            teInit(connection, initString);
+                            break;
+                        case MONITOR_CMD_ACTIVATE:
+                            abandonGetField(connection);
+                            buf = new char[plen-3];
+                            System.arraycopy(packet, 3, buf, 0, plen-3);
+                            teActivate(connection, initString, packet[1], packet[2], buf);
+                            break;
+                        case MONITOR_CMD_KEYSTATE:
+                            teKeyState(connection, (packet[1] == 1));
+                            break;
+                        case MONITOR_CMD_CURSORMOVE:
+                            teCursorMove(connection, packet[1], packet[2], packet[3]);
+                            break;
+                        case MONITOR_CMD_SCREENCHANGE:
+                            buf = new char[plen-3];
+                            System.arraycopy(packet, 3, buf, 0, plen-3);
+                            cleanup(buf);
+                            teScreenChange(connection, packet[1], packet[2], buf);
+                            break;
+                        case MONITOR_CMD_FIELDVALUE:
+                            value_queue.clear();
+                            value_queue.put(reformatValue(packet));
+                            break;
+                        default:
+                            break;
+                    }
+                } catch (IOException e) {
+                    if (!is_closing) Log.e(TAG, "exception in CommunicationThread.run()", e);
+                    break;
+                } catch (InterruptedException e) {
+                    Log.e(TAG, "exception in CommunicationThread.run()", e);
+                    break;
+                }
+            }
+            Log.i(TAG, String.format("shutting down connection %d", connection));
+            try {
+                if (client_in     != null) client_in.close();
+                if (client_out    != null) client_out.close();
+                if (client_socket != null) client_socket.close();
+            } catch (IOException e) {
+                Log.e(TAG, "exception in CommunicationThread.run() closing sockets", e);
+            }
+            client_in     = null;
+            client_out    = null;
+            client_socket = null;
+            clients.remove(connection);
+        }
+    }
+
+    private void abandonGetField(int except) {
+        for (CommunicationThread cm : clients.values()) {
+            if (cm.connection != except) {
+                cm.abandon();
+            }
+        }
+    }
+
+
+    ////////////////////////////////////////
+    //// these functions run on the reader thread here and call your monitoring code
+
+    public void teInit(int connection, String fn) {
+        Log.i(TAG, String.format("teInit %d file %s", connection, fn));
+        printer(String.format("init %d %s", connection, fn));
+        setCurrentConnection(connection);
+    }
+
+    public void teCloseAll() {
+        Log.i(TAG, String.format("teCloseAll"));
+    }
+
+    public void teClose(int connection) {
+        Log.i(TAG, String.format("teClose %d", connection));
+        setCurrentConnection(-1);
+    }
+
+    public void teActivate(int connection, String fn, int lines, int columns, char[] buf) {
+        Log.i(TAG, String.format("teActivate %d", connection));
+        printer(String.format("activate %d lines %d columns %d b.len %d", connection, lines, columns, buf.length));
+        boolean sameinit = false;
+        CommunicationThread cm = clients.get(currentConnection);
+        if (cm != null) {
+            sameinit = (cm.initString == fn);
+        }
+        setCurrentConnection(connection);
+    }
+
+    public void teKeyState(int connection, boolean down) {
+        String d = (down) ? "yes" : "no";
+        Log.i(TAG, String.format("teKeyState %d isdown %s", connection, d));
+        printer(String.format("keystate %d isdown %s", connection, d));
+    }
+
+    public void teCursorMove(int connection, int l, int c, int why) {
+        Log.i(TAG, String.format("teCursorMove %d line %d column %d why %d", connection, l, c, why));
+    }
+
+    public void teScreenChange(int connection, int lines, int columns, char[] buf) {
+        Log.i(TAG, String.format("teScreenChange %d lines %d columns %d b.len %d", connection, lines, columns, buf.length));
+    }
+
+
+    ////////////////////////////////////////
+    //// these functions are called from your monitoring code thread
+
+    public static void teSetField(int connection, int l, int c, char[] buf) {
+        int len = buf.length;
+        Log.i(TAG, String.format("teSetField %d request line %d column %d len %d", connection, l, c, len));
+        CommunicationThread cm = clients.get(connection);
+        if (cm != null) {
+            char[] arg2 = new char[4 + len];
+            arg2[2] = (char) (l & 0x0000ffff);
+            arg2[3] = (char) (c & 0x0000ffff);
+            int base = 4;
+            System.arraycopy(buf, 0, arg2, base, len);
+            cm.clientWrite(MONITOR_CMD_SETFIELD, arg2);
+        }
+    }
+
+    public static char[] teGetField(int connection, int l, int c, int len) {
+        Log.i(TAG, String.format("teGetField %d request line %d column %d len %d", connection, l, c, len));
+        CommunicationThread cm = clients.get(connection);
+        if (cm != null) {
+            char[] arg = new char[5];
+            arg[2] = (char) (l & 0x0000ffff);
+            arg[3] = (char) (c & 0x0000ffff);
+            arg[4] = (char) (len & 0x0000ffff);
+            int request = cm.cmGetField(arg);
+            try {
+                int tid = android.os.Process.myTid();
+                triple t;
+                if (tid == cm.thread_id) {
+                    // we are running on the socket reader thread, called via teCursorMove() or teScreenChange()
+                    // we need to peek command packets from the socket looking for our fieldvalue response
+                    Log.i(TAG, String.format("java teGetField() peeking value for getfield on reader thread"));
+                    t = cm.peekValue(request);
+                }
+                else {
+                    // we are running on some other thread, just wait for the reader thread to
+                    // process the fieldvalue and put it on the queue.
+                    Log.i(TAG, String.format("java teGetField() waiting for data for getfield on reco thread"));
+                    t = cm.value_queue.take(); // wait for response
+                }
+                Log.i(TAG, String.format("teGetField %d response line %d column %d len %d", connection, t.l, t.c, t.b.length));
+                return t.b;
+            } catch (InterruptedException e) {
+                Log.e(TAG, "exception in teGetField(), return empty string", e);
+            }
+        }
+        return new char[0];
+    }
+
+    public static void teScreenWatch(int connection, int l, int c, int len) {
+        Log.i(TAG, String.format("teScreenWatch %d request line %d column %d len %d", connection, l, c, len));
+        CommunicationThread cm = clients.get(connection);
+        if (cm != null) {
+            char[] arg = new char[5];
+            arg[2] = (char) (l & 0x0000ffff);
+            arg[3] = (char) (c & 0x0000ffff);
+            arg[4] = (char) (len & 0x0000ffff);
+            cm.clientWrite(MONITOR_CMD_GETFIELD, arg);
+        }
+    }
+
+    public static void teSpeak(int connection, byte [] msg, boolean flush, boolean synchronous) {
+        CommunicationThread cm = clients.get(connection);
+        if (cm != null) cm.speak(msg, flush, synchronous);
+    }
+
+    public static void teDepress(int connection, int vk_key) {
+        // http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731
+        Log.i(TAG, String.format("teDepress %d, %d", connection, vk_key));
+        CommunicationThread cm = clients.get(connection);
+        if (cm != null) {
+            char[] arg = new char[3];
+            arg[2] = (char) (vk_key & 0x0000ffff);
+            cm.clientWrite(MONITOR_CMD_DEPRESS, arg);
+        }
+    }
+
+    public static void teShowUrl(int connection, char [] url) {
+        int len = url.length;
+        CommunicationThread cm = clients.get(connection);
+        if (cm != null) {
+            char[] arg2 = new char[2 + len];
+            int base = 2;
+            System.arraycopy(url, 0, arg2, base, len);
+            cm.clientWrite(MONITOR_CMD_SHOWURL, arg2);
+        }
+    }
+
+    public static void teAbandonGetField(int connection) {
+        Log.i(TAG, String.format("teAbandonGetField %d", connection));
+        CommunicationThread cm = clients.get(connection);
+        if (cm != null) {
+            cm.abandon();
+        }
+    }
+
+    public static void teSwitchSession(int connection) {
+        CommunicationThread cm = clients.get(connection);
+        if (cm != null) {
+            char [] arg2 = new char[2];
+            cm.clientWrite(MONITOR_CMD_SWITCHSESSION, arg2);
+        }
+    }
+
+    public static void teCursorRequest(int connection) {
+        CommunicationThread cm = clients.get(connection);
+        if (cm != null) {
+            char [] arg2 = new char[2];
+            cm.clientWrite(MONITOR_CMD_CURSORREQUEST, arg2);
+        }
+    }
+
+}
Binary file app/src/main/res/drawable-hdpi/icon.png has changed
Binary file app/src/main/res/drawable-hdpi/notification_icon.png has changed
Binary file app/src/main/res/drawable-ldpi/icon.png has changed
Binary file app/src/main/res/drawable-ldpi/notification_icon.png has changed
Binary file app/src/main/res/drawable-mdpi/icon.png has changed
Binary file app/src/main/res/drawable-mdpi/notification_icon.png has changed
Binary file app/src/main/res/drawable-xhdpi/icon.png has changed
Binary file app/src/main/res/drawable-xhdpi/notification_icon.png has changed
Binary file app/src/main/res/drawable-xxhdpi/icon.png has changed
Binary file app/src/main/res/drawable-xxhdpi/notification_icon.png has changed
Binary file app/src/main/res/drawable-xxxhdpi/icon.png has changed
Binary file app/src/main/res/drawable-xxxhdpi/notification_icon.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/src/main/res/layout/main.xml	Thu Nov 08 11:39:13 2018 -0800
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical" >
+
+    <TextView
+        android:id="@+id/text2"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="" >
+    </TextView>
+
+</LinearLayout>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/src/main/res/menu/main.xml	Thu Nov 08 11:39:13 2018 -0800
@@ -0,0 +1,9 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <item
+        android:id="@+id/action_settings"
+        android:orderInCategory="100"
+        android:showAsAction="never"
+        android:title="@string/action_settings"/>
+
+</menu>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/src/main/res/values-sw600dp/dimens.xml	Thu Nov 08 11:39:13 2018 -0800
@@ -0,0 +1,8 @@
+<resources>
+
+    <!--
+         Customize dimensions originally defined in res/values/dimens.xml (such as
+         screen margins) for sw600dp devices (e.g. 7" tablets) here.
+    -->
+
+</resources>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/src/main/res/values-sw720dp-land/dimens.xml	Thu Nov 08 11:39:13 2018 -0800
@@ -0,0 +1,9 @@
+<resources>
+
+    <!--
+         Customize dimensions originally defined in res/values/dimens.xml (such as
+         screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here.
+    -->
+    <dimen name="activity_horizontal_margin">128dp</dimen>
+
+</resources>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/src/main/res/values-v11/styles.xml	Thu Nov 08 11:39:13 2018 -0800
@@ -0,0 +1,11 @@
+<resources>
+
+    <!--
+        Base application theme for API 11+. This theme completely replaces
+        AppBaseTheme from res/values/styles.xml on API 11+ devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Holo.Light">
+        <!-- API 11 theme customizations can go here. -->
+    </style>
+
+</resources>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/src/main/res/values-v14/styles.xml	Thu Nov 08 11:39:13 2018 -0800
@@ -0,0 +1,12 @@
+<resources>
+
+    <!--
+        Base application theme for API 14+. This theme completely replaces
+        AppBaseTheme from BOTH res/values/styles.xml and
+        res/values-v11/styles.xml on API 14+ devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
+        <!-- API 14 theme customizations can go here. -->
+    </style>
+
+</resources>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/src/main/res/values/dimens.xml	Thu Nov 08 11:39:13 2018 -0800
@@ -0,0 +1,7 @@
+<resources>
+
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
+
+</resources>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/src/main/res/values/strings.xml	Thu Nov 08 11:39:13 2018 -0800
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="app_name">510 Connectbot Monitor</string>
+    <string name="service_desc">Maintains socket connection between 510 Connectbot terminal emulator and the monitoring application.</string>
+    <string name="action_settings">Settings</string>
+    <string name="copyright">Copyright © 2014 by 510 Software Group. Released under the GPLv3 or later. Full source code at http://www.five-ten-sg.com/510ConnectbotMonitor/</string>
+</resources>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/src/main/res/values/styles.xml	Thu Nov 08 11:39:13 2018 -0800
@@ -0,0 +1,20 @@
+<resources>
+
+    <!--
+        Base application theme, dependent on API level. This theme is replaced
+        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Light">
+        <!--
+            Theme customizations available in newer API levels can go in
+            res/values-vXX/styles.xml, while customizations related to
+            backward-compatibility can go here.
+        -->
+    </style>
+
+    <!-- Application theme. -->
+    <style name="AppTheme" parent="AppBaseTheme">
+        <!-- All customizations that are NOT specific to a particular API-level can go here. -->
+    </style>
+
+</resources>
\ No newline at end of file
--- a/build.xml	Fri May 01 12:34:17 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project name="510ConnectbotMonitor" default="help">
-
-    <property file="local.properties" />
-
-    <property file="ant.properties" />
-
-    <loadproperties srcFile="project.properties" />
-
-    <!-- quick check on sdk.dir -->
-    <fail
-            message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var"
-            unless="sdk.dir"
-    />
-
-    <!-- version-tag: custom -->
-    <import file="${sdk.dir}/tools/ant/build.xml" />
-
-</project>
--- a/proguard-project.txt	Fri May 01 12:34:17 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-# To enable ProGuard in your project, edit project.properties
-# to define the proguard.config property as described in that file.
-#
-# Add project specific ProGuard rules here.
-# By default, the flags in this file are appended to flags specified
-# in ${sdk.dir}/tools/proguard/proguard-android.txt
-# You can edit the include path and order by changing the ProGuard
-# include property in project.properties.
-#
-# For more details, see
-#   http://developer.android.com/guide/developing/tools/proguard.html
-
-# Add any project specific keep options here:
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-#   public *;
-#}
--- a/project.properties	Fri May 01 12:34:17 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must be checked in Version Control Systems.
-#
-# To customize properties used by the Ant build system edit
-# "ant.properties", and override values to adapt the script to your
-# project structure.
-#
-
-# Project target.
-target=android-16
Binary file res/drawable-hdpi/icon.png has changed
Binary file res/drawable-hdpi/notification_icon.png has changed
Binary file res/drawable-ldpi/icon.png has changed
Binary file res/drawable-ldpi/notification_icon.png has changed
Binary file res/drawable-mdpi/icon.png has changed
Binary file res/drawable-mdpi/notification_icon.png has changed
Binary file res/drawable-xhdpi/icon.png has changed
Binary file res/drawable-xhdpi/notification_icon.png has changed
Binary file res/drawable-xxhdpi/icon.png has changed
Binary file res/drawable-xxhdpi/notification_icon.png has changed
Binary file res/drawable-xxxhdpi/icon.png has changed
Binary file res/drawable-xxxhdpi/notification_icon.png has changed
--- a/res/layout/main.xml	Fri May 01 12:34:17 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
-    android:orientation="vertical" >
-
-    <TextView
-        android:id="@+id/text2"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:text="" >
-    </TextView>
-
-</LinearLayout>
\ No newline at end of file
--- a/res/menu/main.xml	Fri May 01 12:34:17 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-<menu xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <item
-        android:id="@+id/action_settings"
-        android:orderInCategory="100"
-        android:showAsAction="never"
-        android:title="@string/action_settings"/>
-
-</menu>
\ No newline at end of file
--- a/res/values-sw600dp/dimens.xml	Fri May 01 12:34:17 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-<resources>
-
-    <!--
-         Customize dimensions originally defined in res/values/dimens.xml (such as
-         screen margins) for sw600dp devices (e.g. 7" tablets) here.
-    -->
-
-</resources>
\ No newline at end of file
--- a/res/values-sw720dp-land/dimens.xml	Fri May 01 12:34:17 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-<resources>
-
-    <!--
-         Customize dimensions originally defined in res/values/dimens.xml (such as
-         screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here.
-    -->
-    <dimen name="activity_horizontal_margin">128dp</dimen>
-
-</resources>
\ No newline at end of file
--- a/res/values-v11/styles.xml	Fri May 01 12:34:17 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-<resources>
-
-    <!--
-        Base application theme for API 11+. This theme completely replaces
-        AppBaseTheme from res/values/styles.xml on API 11+ devices.
-    -->
-    <style name="AppBaseTheme" parent="android:Theme.Holo.Light">
-        <!-- API 11 theme customizations can go here. -->
-    </style>
-
-</resources>
\ No newline at end of file
--- a/res/values-v14/styles.xml	Fri May 01 12:34:17 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-<resources>
-
-    <!--
-        Base application theme for API 14+. This theme completely replaces
-        AppBaseTheme from BOTH res/values/styles.xml and
-        res/values-v11/styles.xml on API 14+ devices.
-    -->
-    <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
-        <!-- API 14 theme customizations can go here. -->
-    </style>
-
-</resources>
\ No newline at end of file
--- a/res/values/dimens.xml	Fri May 01 12:34:17 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-<resources>
-
-    <!-- Default screen margins, per the Android Design guidelines. -->
-    <dimen name="activity_horizontal_margin">16dp</dimen>
-    <dimen name="activity_vertical_margin">16dp</dimen>
-
-</resources>
\ No newline at end of file
--- a/res/values/strings.xml	Fri May 01 12:34:17 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-    <string name="app_name">510 Connectbot Monitor</string>
-    <string name="service_desc">Maintains socket connection between 510 Connectbot terminal emulator and the monitoring application.</string>
-    <string name="action_settings">Settings</string>
-    <string name="copyright">Copyright © 2014 by 510 Software Group. Released under the GPLv3 or later. Full source code at http://www.five-ten-sg.com/510ConnectbotMonitor/</string>
-</resources>
--- a/res/values/styles.xml	Fri May 01 12:34:17 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-<resources>
-
-    <!--
-        Base application theme, dependent on API level. This theme is replaced
-        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
-    -->
-    <style name="AppBaseTheme" parent="android:Theme.Light">
-        <!--
-            Theme customizations available in newer API levels can go in
-            res/values-vXX/styles.xml, while customizations related to
-            backward-compatibility can go here.
-        -->
-    </style>
-
-    <!-- Application theme. -->
-    <style name="AppTheme" parent="AppBaseTheme">
-        <!-- All customizations that are NOT specific to a particular API-level can go here. -->
-    </style>
-
-</resources>
\ No newline at end of file
--- a/src/com/five_ten_sg/connectbot/monitor/MonitorActivity.java	Fri May 01 12:34:17 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
-package com.five_ten_sg.connectbot.monitor;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.net.ServerSocket;
-import java.net.Socket;
-
-import android.app.Activity;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.net.wifi.WifiManager.WifiLock;
-import android.net.wifi.WifiManager;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Environment;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.PowerManager;
-import android.util.Log;
-import android.widget.TextView;
-
-public class MonitorActivity extends Activity {
-    public final static String TAG = "ConnectBot.MonitorActivity";
-
-    public static final int MESSAGE_CODE_PRINT = 6000;
-    private final int       LINES = 20;
-    private String[]        texts   = new String[LINES];
-    private int             start   = 0;
-    private int             count   = 0;
-    private TextView        text    = null;
-    private MonitorService  bound   = null;
-    private Handler         handler = new Handler() {
-        @Override
-        public void handleMessage (Message msg) {
-            if (msg.what == MESSAGE_CODE_PRINT) {
-                printer((String)msg.obj);
-            } else {
-                super.handleMessage(msg);
-            }
-        }
-    };
-    private ServiceConnection connection = new ServiceConnection() {
-        public void onServiceConnected(ComponentName className, IBinder service) {
-            Log.i(TAG, "onServiceConnected()");
-            bound = ((MonitorService.MonitorBinder)service).getService();
-            bound.handler = handler;
-        }
-        public void onServiceDisconnected(ComponentName className) {
-            Log.i(TAG, "onServiceDisconnected()");
-            bound = null;
-        }
-    };
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.main);
-        text = (TextView) findViewById(R.id.text2);
-        printer(getString(R.string.copyright));
-        String external_dir = Environment.getExternalStorageDirectory().getAbsolutePath();
-        printer("");
-        printer(String.format("External directory is %s", external_dir));
-        printer("");
-        Log.i(TAG, "binding to monitor service");
-        Intent intent = new Intent ("com.five_ten_sg.connectbot.monitor.MonitorService");
-        bindService(intent, connection, Context.BIND_AUTO_CREATE);
-    }
-
-    private void printer(String msg) {
-        if (count < LINES) count++;
-        else               start = (start+1) % LINES;
-        texts[(start+count-1) % LINES] = msg + "\n";
-        String c = "";
-        for (int i=0; i<count; i++) c = c.concat(texts[(start+i) % LINES]);
-        text.setText(c);
-    }
-
-    @Override
-    protected void onStart() {
-        super.onStart();
-        Log.i(TAG, "activity onStart()");
-    }
-
-    @Override
-    protected void onRestart() {
-        super.onRestart();
-        Log.i(TAG, "activity onRestart()");
-    }
-
-    @Override
-    protected void onStop() {
-        super.onStop();
-        Log.i(TAG, "activity onStop()");
-    }
-
-    @Override
-    protected void onDestroy() {
-        Log.i(TAG, "activity onDestroy()");
-        unbindService(connection);
-        super.onDestroy();
-    }
-}
--- a/src/com/five_ten_sg/connectbot/monitor/MonitorService.java	Fri May 01 12:34:17 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,593 +0,0 @@
-package com.five_ten_sg.connectbot.monitor;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.util.HashMap;
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.Locale;
-
-import android.app.Activity;
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.net.wifi.WifiManager.WifiLock;
-import android.net.wifi.WifiManager;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.PowerManager;
-import android.speech.tts.TextToSpeech;
-import android.speech.tts.TextToSpeech.OnInitListener;
-import android.util.Log;
-import android.widget.TextView;
-
-public class MonitorService extends Service implements OnInitListener {
-    public final static String TAG = "ConnectBot.MonitorService";
-
-    public  static final char MONITOR_CMD_INIT          = 0;
-    public  static final char MONITOR_CMD_ACTIVATE      = 1;
-    public  static final char MONITOR_CMD_KEYSTATE      = 2;
-    public  static final char MONITOR_CMD_CURSORMOVE    = 3;
-    public  static final char MONITOR_CMD_SCREENCHANGE  = 4;
-    public  static final char MONITOR_CMD_FIELDVALUE    = 5;
-    public  static final char MONITOR_CMD_SETFIELD      = 5;
-    public  static final char MONITOR_CMD_GETFIELD      = 6;
-    public  static final char MONITOR_CMD_SCREENWATCH   = 7;
-    public  static final char MONITOR_CMD_DEPRESS       = 8;
-    public  static final char MONITOR_CMD_SHOWURL       = 9;
-    public  static final char MONITOR_CMD_SWITCHSESSION = 10;
-    public  static final char MONITOR_CMD_CURSORREQUEST = 11;
-
-    public  static final char CURSOR_REQUESTED      = 0;
-    public  static final char CURSOR_SCREEN_CHANGE  = 1;
-    public  static final char CURSOR_USER_KEY       = 2;
-
-    public static final int       MONITORPORT = 6000;
-    public static ConcurrentHashMap<Integer,CommunicationThread> clients = new ConcurrentHashMap<Integer,CommunicationThread>();
-    public static int             currentConnection = -1;
-
-    private boolean               speech  = false;
-    private TextToSpeech          talker  = null;
-    private BlockingQueue<String> talkerQueue = null;
-    public  Handler               handler = null;
-    private ServerSocket          serverSocket;
-    private Thread                serverThread = null;
-    private WifiManager.WifiLock  wifiLock;
-    private PowerManager.WakeLock wakeLock;
-    final private IBinder         binder = new MonitorBinder();
-
-
-    public class MonitorBinder extends Binder {
-        public MonitorService getService() {
-            return MonitorService.this;
-        }
-    }
-
-    @Override
-    public void onInit(int status) {
-        if (status == TextToSpeech.SUCCESS) {
-            talker.setLanguage(Locale.US);
-            speech = true;
-        }
-    }
-
-    @Override
-    public void onCreate() {
-        WifiManager wMgr = (WifiManager) getSystemService(Context.WIFI_SERVICE);
-        wifiLock = wMgr.createWifiLock(WifiManager.WIFI_MODE_FULL, "MyWifiLock");
-        wifiLock.acquire();
-
-        PowerManager pMgr = (PowerManager) getSystemService(Context.POWER_SERVICE);
-        wakeLock = pMgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
-        wakeLock.acquire();
-
-        talker = new TextToSpeech(this, this);
-        this.serverThread = new Thread(new ServerThread());
-        this.serverThread.start();
-    }
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        startService(new Intent(this, MonitorService.class));
-        return binder;
-    }
-
-    public void printer(String msg) {
-        if (handler != null) handler.sendMessage(handler.obtainMessage(MonitorActivity.MESSAGE_CODE_PRINT, msg));
-    }
-
-    public synchronized void setCurrentConnection(int connection) {
-        currentConnection = connection;
-    }
-
-    public synchronized int nextConnection() {
-        int c = 1;
-        while (clients.get(c) != null) c++;
-        return c;
-    }
-
-    @Override
-    public int onStartCommand(Intent intent, int flags, int startId) {
-        Log.i(TAG, "service onStartCommand()");
-        return START_STICKY;
-    }
-
-    @Override
-    public void onDestroy() {
-        try {
-            Log.i(TAG, "service onDestroy()");
-            teCloseAll();
-            talker.stop();
-            talker.shutdown();
-            wifiLock.release();
-            wakeLock.release();
-            serverSocket.close();
-        } catch (IOException e) {
-            Log.e(TAG, "exception in onDestroy()", e);
-        }
-        super.onDestroy();
-    }
-
-    class ServerThread extends Thread {
-        public void run() {
-            Socket  socket = null;
-            int connection = 0;
-            try {
-                serverSocket = new ServerSocket(MONITORPORT);
-            } catch (IOException e) {
-                Log.e(TAG, "exception in ServerThread.run(), cannot create listening socket", e);
-                return;
-            }
-            while (true) {
-                try{
-                   socket     = serverSocket.accept();
-                   connection = nextConnection();
-                   CommunicationThread commThread = new CommunicationThread(connection, socket);
-                   clients.put(connection, commThread);
-                   commThread.start();
-                } catch (IOException e) {
-                   Log.e(TAG, "exception in ServerThread.run(), listening socket closed", e);
-                   break;
-                }
-            }
-        }
-    }
-
-    class triple {
-        private int l, c;
-        private char[] b;
-        public triple(int l, int c, char[] b) {
-            this.l = l;
-            this.c = c;
-            this.b = b;
-        }
-    }
-
-    class CommunicationThread extends Thread {
-        public  int            thread_id;
-        public  int            connection;
-        private String         initString = null;
-        private Socket         client_socket;
-        private InputStream    client_in;
-        private OutputStream   client_out;
-        private boolean        is_closing = false;
-        private Integer        getfields_outstanding = 0;
-        private BlockingQueue<triple>  value_queue = new ArrayBlockingQueue<triple>(1);
-        private BlockingQueue<char[]>  packet_queue = new ArrayBlockingQueue<char[]>(10000);
-
-        public CommunicationThread(int handle, Socket socket) {
-            connection    = handle;
-            client_socket = socket;
-            try {
-                client_in  = client_socket.getInputStream();
-                client_out = client_socket.getOutputStream();
-            } catch (IOException e) {
-                Log.e(TAG, "exception in CommunicationThread() constructor, cannot get socket streams", e);
-            }
-        }
-
-        public synchronized void abandon() {
-            value_queue.offer(new triple(0, 0, new char[0]));
-        }
-
-        public void speak(byte [] msg, boolean flush, boolean synchronous) {
-            if (speech) {
-                String smsg = bytesToString(msg);
-                if (synchronous) {
-                    HashMap<String, String> myHashParms = new HashMap();
-                    myHashParms.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, String.format("connection %d", connection));
-                	talker.speak(smsg, (flush) ? TextToSpeech.QUEUE_FLUSH : TextToSpeech.QUEUE_ADD, myHashParms);
-                    try {
-                        String x = talkerQueue.take(); // wait for completion
-                    } catch (InterruptedException e) {
-                        Log.e(TAG, "exception in cm.speak()", e);
-                    }
-                }
-                else {
-            	    talker.speak(smsg, (flush) ? TextToSpeech.QUEUE_FLUSH : TextToSpeech.QUEUE_ADD, null);
-                }
-            }
-        }
-
-        public String bytesToString(byte[] b) {
-            char[] c = new char[b.length];
-            int bp = 0;
-            for(int i = 0; i < c.length; i++) {
-                byte b1 = 0;
-                byte b2 = b[bp++];
-                c[i] = (char) (((b1 & 0x00FF) << 8) + (b2 & 0x00FF));
-            }
-            return new String(c);
-        }
-
-        public char[] bytesToChars(byte[] b, int len) {
-            char[] c = new char[len >> 1];
-            int bp = 0;
-            for(int i = 0; i < c.length; i++) {
-                byte b1 = b[bp++];
-                byte b2 = b[bp++];
-                c[i] = (char) (((b1 & 0x00FF) << 8) + (b2 & 0x00FF));
-            }
-            return c;
-        }
-
-        public byte[] charsToBytes(char[] c) {
-            byte[] b = new byte[c.length << 1];
-            int bp = 0;
-            for (int i=0; i<c.length; i++) {
-                b[bp++] = (byte) ((c[i] & 0xff00) >> 8);
-                b[bp++] = (byte)  (c[i] & 0x00ff);
-            }
-            return b;
-        }
-
-        void cleanup(char[] buf) {
-            int i;
-            for (i=0; i<buf.length; i++) {
-                if ((int)(buf[i]) < 32) buf[i] = ' ';
-            }
-        }
-
-        public int cmGetField(char[] c) {
-            int request;
-            synchronized(getfields_outstanding) {
-                request = getfields_outstanding;
-                getfields_outstanding = getfields_outstanding + 1;
-                value_queue.clear();  // we never have more than one outstanding getfield request from the reco thread on the connection
-                clientWrite(MONITOR_CMD_GETFIELD, c);
-            }
-            return request;
-        }
-
-        public synchronized void clientWrite(char cmd, char[] c) {
-            try {
-                if (client_out != null) {
-                    c[0] = (char)(c.length - 1);    // number of chars following
-                    c[1] = cmd;
-                    Log.i(TAG, String.format("sending %d command", (int)cmd));
-                    client_out.write(charsToBytes(c));
-                    client_out.flush();
-                }
-            }
-            catch (IOException e) {
-                Log.e(TAG, "exception in monitorWrite()", e);
-                try {
-                    client_out.close();
-                }
-                catch (IOException ee) {
-                    Log.e(TAG, "exception in monitorWrite() closing socket", ee);
-                }
-                client_out = null;
-            }
-        };
-
-        private char[] forceRead(int len) throws IOException {
-            int len2 = len*2;
-            int off  = 0;
-            byte[] b = new byte[len2];
-            while (off < len2) {
-                int l = client_in.read(b, off, len2-off);
-                if (l < 0) {
-                    is_closing = true;
-                    throw new IOException("eof");
-                }
-                off += l;
-            }
-            return bytesToChars(b, len2);
-        }
-
-        public char[] readPacket() throws IOException {
-            char[] len = forceRead(1);
-            return forceRead(len[0]);
-        }
-
-        public char[] nextPacket() throws IOException, InterruptedException {
-            char[] packet = packet_queue.poll();
-            if (packet == null) {
-                packet = readPacket();
-                if (packet[0] == MONITOR_CMD_FIELDVALUE) {
-                    synchronized(getfields_outstanding) {
-                        getfields_outstanding = getfields_outstanding - 1;
-                    }
-                }
-            }
-            return packet;
-        }
-
-        private triple reformatValue(char[] packet) {
-            int plen = packet.length;
-            char[] buf = new char[plen-3];
-            System.arraycopy(packet, 3, buf, 0, plen-3);
-            cleanup(buf);
-            Log.i(TAG, String.format("teFieldValue %d line %d column %d b.len %d", connection, (int)packet[1], (int)packet[2], buf.length));
-            return new triple(packet[1], packet[2], buf);
-        }
-
-        public triple peekValue(int request) {
-            try {
-                while (true) {
-                    char[] packet = readPacket();
-                    if (packet[0] == MONITOR_CMD_FIELDVALUE) {
-                        synchronized(getfields_outstanding) {
-                            getfields_outstanding = getfields_outstanding - 1;
-                            if (request == 0) {
-                                return reformatValue(packet);
-                            }
-                            else {
-                                packet_queue.put(packet);
-                                request = request - 1;
-                            }
-                        }
-                    }
-                    else {
-                        packet_queue.put(packet);
-                    }
-                }
-            } catch (IOException e) {
-                return new triple(0, 0, new char[0]);
-            } catch (InterruptedException e) {
-                return new triple(0, 0, new char[0]);
-            }
-        }
-
-        public void run() {
-            thread_id = android.os.Process.myTid();
-            Log.i(TAG, String.format("CommunicationThread.run() client %d connected", connection));
-            while (true) {
-                try {
-                    char[] packet = nextPacket();
-                    char[] buf;
-                    char cmd = packet[0];
-                    int plen = packet.length;
-                    //Log.i(TAG, String.format("received %d command length %d", (int)cmd, plen));
-                    switch (cmd) {
-                        case MONITOR_CMD_INIT:
-                            buf = new char[plen-1];
-                            System.arraycopy(packet, 1, buf, 0, plen-1);
-                            abandonGetField(connection);
-                            initString = new String(buf);
-                            teInit(connection, initString);
-                            break;
-                        case MONITOR_CMD_ACTIVATE:
-                            abandonGetField(connection);
-                            buf = new char[plen-3];
-                            System.arraycopy(packet, 3, buf, 0, plen-3);
-                            teActivate(connection, initString, packet[1], packet[2], buf);
-                            break;
-                        case MONITOR_CMD_KEYSTATE:
-                            teKeyState(connection, (packet[1] == 1));
-                            break;
-                        case MONITOR_CMD_CURSORMOVE:
-                            teCursorMove(connection, packet[1], packet[2], packet[3]);
-                            break;
-                        case MONITOR_CMD_SCREENCHANGE:
-                            buf = new char[plen-3];
-                            System.arraycopy(packet, 3, buf, 0, plen-3);
-                            cleanup(buf);
-                            teScreenChange(connection, packet[1], packet[2], buf);
-                            break;
-                        case MONITOR_CMD_FIELDVALUE:
-                            value_queue.clear();
-                            value_queue.put(reformatValue(packet));
-                            break;
-                        default:
-                            break;
-                    }
-                } catch (IOException e) {
-                    if (!is_closing) Log.e(TAG, "exception in CommunicationThread.run()", e);
-                    break;
-                } catch (InterruptedException e) {
-                    Log.e(TAG, "exception in CommunicationThread.run()", e);
-                    break;
-                }
-            }
-            Log.i(TAG, String.format("shutting down connection %d", connection));
-            try {
-                if (client_in     != null) client_in.close();
-                if (client_out    != null) client_out.close();
-                if (client_socket != null) client_socket.close();
-            } catch (IOException e) {
-                Log.e(TAG, "exception in CommunicationThread.run() closing sockets", e);
-            }
-            client_in     = null;
-            client_out    = null;
-            client_socket = null;
-            clients.remove(connection);
-        }
-    }
-
-    private void abandonGetField(int except) {
-        for (CommunicationThread cm : clients.values()) {
-            if (cm.connection != except) {
-                cm.abandon();
-            }
-        }
-    }
-
-
-    ////////////////////////////////////////
-    //// these functions run on the reader thread here and call your monitoring code
-
-    public void teInit(int connection, String fn) {
-        Log.i(TAG, String.format("teInit %d file %s", connection, fn));
-        printer(String.format("init %d %s", connection, fn));
-        setCurrentConnection(connection);
-    }
-
-    public void teCloseAll() {
-        Log.i(TAG, String.format("teCloseAll"));
-    }
-
-    public void teClose(int connection) {
-        Log.i(TAG, String.format("teClose %d", connection));
-        setCurrentConnection(-1);
-    }
-
-    public void teActivate(int connection, String fn, int lines, int columns, char[] buf) {
-        Log.i(TAG, String.format("teActivate %d", connection));
-        printer(String.format("activate %d lines %d columns %d b.len %d", connection, lines, columns, buf.length));
-        boolean sameinit = false;
-        CommunicationThread cm = clients.get(currentConnection);
-        if (cm != null) {
-            sameinit = (cm.initString == fn);
-        }
-        setCurrentConnection(connection);
-    }
-
-    public void teKeyState(int connection, boolean down) {
-        String d = (down) ? "yes" : "no";
-        Log.i(TAG, String.format("teKeyState %d isdown %s", connection, d));
-        printer(String.format("keystate %d isdown %s", connection, d));
-    }
-
-    public void teCursorMove(int connection, int l, int c, int why) {
-        Log.i(TAG, String.format("teCursorMove %d line %d column %d why %d", connection, l, c, why));
-    }
-
-    public void teScreenChange(int connection, int lines, int columns, char[] buf) {
-        Log.i(TAG, String.format("teScreenChange %d lines %d columns %d b.len %d", connection, lines, columns, buf.length));
-    }
-
-
-    ////////////////////////////////////////
-    //// these functions are called from your monitoring code thread
-
-    public static void teSetField(int connection, int l, int c, char[] buf) {
-        int len = buf.length;
-        Log.i(TAG, String.format("teSetField %d request line %d column %d len %d", connection, l, c, len));
-        CommunicationThread cm = clients.get(connection);
-        if (cm != null) {
-            char[] arg2 = new char[4 + len];
-            arg2[2] = (char) (l & 0x0000ffff);
-            arg2[3] = (char) (c & 0x0000ffff);
-            int base = 4;
-            System.arraycopy(buf, 0, arg2, base, len);
-            cm.clientWrite(MONITOR_CMD_SETFIELD, arg2);
-        }
-    }
-
-    public static char[] teGetField(int connection, int l, int c, int len) {
-        Log.i(TAG, String.format("teGetField %d request line %d column %d len %d", connection, l, c, len));
-        CommunicationThread cm = clients.get(connection);
-        if (cm != null) {
-            char[] arg = new char[5];
-            arg[2] = (char) (l & 0x0000ffff);
-            arg[3] = (char) (c & 0x0000ffff);
-            arg[4] = (char) (len & 0x0000ffff);
-            int request = cm.cmGetField(arg);
-            try {
-                int tid = android.os.Process.myTid();
-                triple t;
-                if (tid == cm.thread_id) {
-                    // we are running on the socket reader thread, called via teCursorMove() or teScreenChange()
-                    // we need to peek command packets from the socket looking for our fieldvalue response
-                    Log.i(TAG, String.format("java teGetField() peeking value for getfield on reader thread"));
-                    t = cm.peekValue(request);
-                }
-                else {
-                    // we are running on some other thread, just wait for the reader thread to
-                    // process the fieldvalue and put it on the queue.
-                    Log.i(TAG, String.format("java teGetField() waiting for data for getfield on reco thread"));
-                    t = cm.value_queue.take(); // wait for response
-                }
-                Log.i(TAG, String.format("teGetField %d response line %d column %d len %d", connection, t.l, t.c, t.b.length));
-                return t.b;
-            } catch (InterruptedException e) {
-                Log.e(TAG, "exception in teGetField(), return empty string", e);
-            }
-        }
-        return new char[0];
-    }
-
-    public static void teScreenWatch(int connection, int l, int c, int len) {
-        Log.i(TAG, String.format("teScreenWatch %d request line %d column %d len %d", connection, l, c, len));
-        CommunicationThread cm = clients.get(connection);
-        if (cm != null) {
-            char[] arg = new char[5];
-            arg[2] = (char) (l & 0x0000ffff);
-            arg[3] = (char) (c & 0x0000ffff);
-            arg[4] = (char) (len & 0x0000ffff);
-            cm.clientWrite(MONITOR_CMD_GETFIELD, arg);
-        }
-    }
-
-    public static void teSpeak(int connection, byte [] msg, boolean flush, boolean synchronous) {
-        CommunicationThread cm = clients.get(connection);
-        if (cm != null) cm.speak(msg, flush, synchronous);
-    }
-
-    public static void teDepress(int connection, int vk_key) {
-        // http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731
-        Log.i(TAG, String.format("teDepress %d, %d", connection, vk_key));
-        CommunicationThread cm = clients.get(connection);
-        if (cm != null) {
-            char[] arg = new char[3];
-            arg[2] = (char) (vk_key & 0x0000ffff);
-            cm.clientWrite(MONITOR_CMD_DEPRESS, arg);
-        }
-    }
-
-    public static void teShowUrl(int connection, char [] url) {
-        int len = url.length;
-        CommunicationThread cm = clients.get(connection);
-        if (cm != null) {
-            char[] arg2 = new char[2 + len];
-            int base = 2;
-            System.arraycopy(url, 0, arg2, base, len);
-            cm.clientWrite(MONITOR_CMD_SHOWURL, arg2);
-        }
-    }
-
-    public static void teAbandonGetField(int connection) {
-        Log.i(TAG, String.format("teAbandonGetField %d", connection));
-        CommunicationThread cm = clients.get(connection);
-        if (cm != null) {
-            cm.abandon();
-        }
-    }
-
-    public static void teSwitchSession(int connection) {
-        CommunicationThread cm = clients.get(connection);
-        if (cm != null) {
-            char [] arg2 = new char[2];
-            cm.clientWrite(MONITOR_CMD_SWITCHSESSION, arg2);
-        }
-    }
-
-    public static void teCursorRequest(int connection) {
-        CommunicationThread cm = clients.get(connection);
-        if (cm != null) {
-            char [] arg2 = new char[2];
-            cm.clientWrite(MONITOR_CMD_CURSORREQUEST, arg2);
-        }
-    }
-
-}