From 9821fd17d0b1f10c87bcfa8e1bf3ff481b2c65b6 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Fri, 12 Jun 2009 10:46:21 +0000 Subject: Charset changes * Simplify charset decoding * Allow changing of charsets while host is connected git-svn-id: https://connectbot.googlecode.com/svn/trunk/connectbot@285 df292f66-193f-0410-a5fc-6d59da041ff2 --- src/org/connectbot/HostEditorActivity.java | 50 ++++++++++-- src/org/connectbot/service/Relay.java | 103 +++---------------------- src/org/connectbot/service/TerminalBridge.java | 9 +++ 3 files changed, 64 insertions(+), 98 deletions(-) (limited to 'src/org') diff --git a/src/org/connectbot/HostEditorActivity.java b/src/org/connectbot/HostEditorActivity.java index 9f38ecc..70dd5b3 100644 --- a/src/org/connectbot/HostEditorActivity.java +++ b/src/org/connectbot/HostEditorActivity.java @@ -26,16 +26,23 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import org.connectbot.bean.HostBean; +import org.connectbot.service.TerminalBridge; +import org.connectbot.service.TerminalManager; import org.connectbot.util.HostDatabase; import org.connectbot.util.PubkeyDatabase; +import android.content.ComponentName; import android.content.ContentValues; +import android.content.Context; import android.content.Intent; +import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; +import android.os.IBinder; import android.preference.CheckBoxPreference; import android.preference.ListPreference; import android.preference.Preference; @@ -199,25 +206,28 @@ public class HostEditorActivity extends PreferenceActivity implements OnSharedPr } - @Override public SharedPreferences getSharedPreferences(String name, int mode) { //Log.d(this.getClass().toString(), String.format("getSharedPreferences(name=%s)", name)); return this.pref; } + protected static final String TAG = "ConnectBot.HostEditorActivity"; + protected HostDatabase hostdb = null; private PubkeyDatabase pubkeydb = null; private CursorPreferenceHack pref; - private String[] colorValues; - private String[] colors; + private ServiceConnection connection; + + private HostBean host; + protected TerminalBridge hostBridge; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); - long id = this.getIntent().getLongExtra(Intent.EXTRA_TITLE, -1); + long hostId = this.getIntent().getLongExtra(Intent.EXTRA_TITLE, -1); // TODO: we could pass through a specific ContentProvider uri here //this.getPreferenceManager().setSharedPreferencesName(uri); @@ -225,7 +235,27 @@ public class HostEditorActivity extends PreferenceActivity implements OnSharedPr this.hostdb = new HostDatabase(this); this.pubkeydb = new PubkeyDatabase(this); - this.pref = new CursorPreferenceHack(HostDatabase.TABLE_HOSTS, id); + host = hostdb.findHostById(hostId); + + connection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + TerminalManager bound = ((TerminalManager.TerminalBinder) service).getService(); + + for (TerminalBridge bridge: bound.bridges) { + if (bridge.host.equals(host)) { + hostBridge = bridge; + Log.d(TAG, "Found host bridge; charset updates will be made live"); + break; + } + } + } + + public void onServiceDisconnected(ComponentName name) { + hostBridge = null; + } + }; + + this.pref = new CursorPreferenceHack(HostDatabase.TABLE_HOSTS, hostId); this.pref.registerOnSharedPreferenceChangeListener(this); this.addPreferencesFromResource(R.xml.host_prefs); @@ -272,6 +302,9 @@ public class HostEditorActivity extends PreferenceActivity implements OnSharedPr @Override public void onStart() { super.onStart(); + + bindService(new Intent(this, TerminalManager.class), connection, Context.BIND_AUTO_CREATE); + if(this.hostdb == null) this.hostdb = new HostDatabase(this); @@ -283,6 +316,9 @@ public class HostEditorActivity extends PreferenceActivity implements OnSharedPr @Override public void onStop() { super.onStop(); + + unbindService(connection); + if(this.hostdb != null) { this.hostdb.close(); this.hostdb = null; @@ -332,6 +368,10 @@ public class HostEditorActivity extends PreferenceActivity implements OnSharedPr // update values on changed preference this.updateSummaries(); + // Our CursorPreferenceHack always send null keys, so try to set charset anyway + if (hostBridge != null) + hostBridge.setCharset(sharedPreferences + .getString(HostDatabase.FIELD_HOST_ENCODING, HostDatabase.ENCODING_DEFAULT)); } } diff --git a/src/org/connectbot/service/Relay.java b/src/org/connectbot/service/Relay.java index 942de88..3bb89b9 100644 --- a/src/org/connectbot/service/Relay.java +++ b/src/org/connectbot/service/Relay.java @@ -26,7 +26,6 @@ import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; -import java.nio.charset.CoderResult; import java.nio.charset.CodingErrorAction; import android.util.Log; @@ -52,8 +51,8 @@ public class Relay implements Runnable { private TerminalBridge bridge; + private Charset currentCharset; private CharsetDecoder decoder; - private CharsetDecoder replacer; private Session session; @@ -78,22 +77,22 @@ public class Relay implements Runnable { } public void setCharset(String encoding) { + Log.d("ConnectBot.Relay", "changing charset to " + encoding); Charset charset; if (encoding.equals(Cp437.NAME)) charset = new Cp437(); else charset = Charset.forName(encoding); + if (charset == currentCharset) + return; + CharsetDecoder newCd = charset.newDecoder(); newCd.onUnmappableCharacter(CodingErrorAction.REPLACE); - newCd.onMalformedInput(CodingErrorAction.REPORT); - - CharsetDecoder newReplacer = charset.newDecoder(); - newReplacer.onUnmappableCharacter(CodingErrorAction.REPLACE); - newReplacer.onMalformedInput(CodingErrorAction.REPLACE); + newCd.onMalformedInput(CodingErrorAction.REPLACE); + currentCharset = charset; decoder = newCd; - replacer = newReplacer; } public void run() { @@ -104,7 +103,6 @@ public class Relay implements Runnable { charArray = charBuffer.array(); int bytesRead = 0; - int offset = 0; int newConditions = 0; @@ -113,28 +111,12 @@ public class Relay implements Runnable { newConditions = session.waitForCondition(CONDITIONS, 0); if ((newConditions & ChannelCondition.STDOUT_DATA) != 0) { while (stdout.available() > 0) { - bytesRead = offset + stdout.read(byteArray, offset, BUFFER_SIZE - offset); + bytesRead = stdout.read(byteArray, 0, BUFFER_SIZE); byteBuffer.position(0); byteBuffer.limit(bytesRead); - - CoderResult coderResult = decoder.decode(byteBuffer, charBuffer, true); - - while (byteBuffer.position() < bytesRead) { - if (coderResult.isMalformed()) - skipMalformedBytes(bytesRead, coderResult); - - coderResult = decoder.decode(byteBuffer, charBuffer, true); - } - - if (coderResult.isMalformed()) - offset = discardMalformedBytes(bytesRead, coderResult); - else { - // No errors at all. - buffer.putString(charArray, 0, charBuffer.position()); - offset = 0; - } - + decoder.decode(byteBuffer, charBuffer, false); + buffer.putString(charArray, 0, charBuffer.position()); charBuffer.clear(); } @@ -156,69 +138,4 @@ public class Relay implements Runnable { } } } - - /** - * @param stream -\ * @throws IOException - */ - private void logAndDiscard(InputStream stream) throws IOException { - while (stream.available() > 0) { - int n = stream.read(byteArray); - byteBuffer.position(0); - byteBuffer.limit(n); - replacer.decode(byteBuffer, charBuffer, false); - // TODO I don't know.. do we want this? We were ignoring it before - Log.d(TAG, String.format("Read data from stream: %s", new String(charArray, 0, charBuffer.position()))); - charBuffer.clear(); - } - } - - /** - * @param n - * @param cr - * @return - */ - private int discardMalformedBytes(int n, CoderResult cr) { - int offset; - /* If we still have malformed input, save the bytes for the next - * read and try to parse it again. - */ - offset = n - byteBuffer.position() + cr.length(); - System.arraycopy(byteArray, byteBuffer.position() - cr.length(), byteArray, 0, offset); - Log.d(TAG, String.format("Copying out %d chars at %d: 0x%02x", - offset, byteBuffer.position() - cr.length(), - byteArray[byteBuffer.position() - cr.length()] - )); - return offset; - } - - /** - * @param numReadBytes - * @param errorResult - */ - private void skipMalformedBytes(int numReadBytes, CoderResult errorResult) { - int curpos = byteBuffer.position() - errorResult.length(); - - if (curpos > 0) { - /* There is good data before the malformed section, so - * pass this on immediately. - */ - buffer.putString(charArray, 0, charBuffer.position()); - } - - byteBuffer.position(curpos); - byteBuffer.limit(curpos + errorResult.length()); - - charBuffer.clear(); - replacer.decode(byteBuffer, charBuffer, true); - - buffer.putString(charArray, 0, charBuffer.position()); - - curpos += errorResult.length(); - - byteBuffer.position(curpos); - byteBuffer.limit(numReadBytes); - - charBuffer.clear(); - } } diff --git a/src/org/connectbot/service/TerminalBridge.java b/src/org/connectbot/service/TerminalBridge.java index 82d1ce5..ec0a35c 100644 --- a/src/org/connectbot/service/TerminalBridge.java +++ b/src/org/connectbot/service/TerminalBridge.java @@ -603,6 +603,15 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal return responses; } + /** + * Sets the encoding used by the terminal. If the connection is live, + * then the character set is changed for the next read. + * @param encoding the canonical name of the character encoding + */ + public void setCharset(String encoding) { + relay.setCharset(encoding); + } + /** * Convenience method for writing a line into the underlying MUD buffer. * Should never be called once the session is established. -- cgit v1.2.3