aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/com/nullwire/trace/ExceptionClickListener.java4
-rw-r--r--src/com/trilead/ssh2/channel/DynamicAcceptThread.java2
-rw-r--r--src/com/trilead/ssh2/channel/LocalAcceptThread.java2
-rw-r--r--src/com/trilead/ssh2/channel/RemoteAcceptThread.java2
-rw-r--r--src/com/trilead/ssh2/channel/RemoteX11AcceptThread.java2
-rw-r--r--src/com/trilead/ssh2/channel/StreamForwarder.java21
-rw-r--r--src/com/trilead/ssh2/compression/CompressionFactory.java2
-rw-r--r--src/com/trilead/ssh2/compression/ICompressor.java2
-rw-r--r--src/com/trilead/ssh2/compression/Zlib.java4
-rw-r--r--src/com/trilead/ssh2/compression/ZlibOpenSSH.java35
-rw-r--r--src/com/trilead/ssh2/transport/TransportConnection.java19
-rw-r--r--src/de/mud/terminal/vt320.java9
-rw-r--r--src/org/connectbot/ConsoleActivity.java110
-rw-r--r--src/org/connectbot/HostEditorActivity.java13
-rw-r--r--src/org/connectbot/HostListActivity.java3
-rw-r--r--src/org/connectbot/PortForwardListActivity.java7
-rw-r--r--src/org/connectbot/PubkeyListActivity.java2
-rw-r--r--src/org/connectbot/StrictModeSetup.java23
-rwxr-xr-xsrc/org/connectbot/TerminalView.java20
-rw-r--r--src/org/connectbot/service/ConnectionNotifier.java39
-rw-r--r--src/org/connectbot/service/ConnectivityReceiver.java43
-rw-r--r--src/org/connectbot/service/Relay.java28
-rw-r--r--src/org/connectbot/service/TerminalBridge.java37
-rw-r--r--src/org/connectbot/service/TerminalKeyListener.java157
-rw-r--r--src/org/connectbot/service/TerminalManager.java51
-rw-r--r--src/org/connectbot/util/EastAsianWidth.java65
-rw-r--r--src/org/connectbot/util/HostDatabase.java59
-rw-r--r--src/org/connectbot/util/PreferenceConstants.java2
-rw-r--r--src/org/connectbot/util/UberColorPickerDialog.java4
29 files changed, 525 insertions, 242 deletions
diff --git a/src/com/nullwire/trace/ExceptionClickListener.java b/src/com/nullwire/trace/ExceptionClickListener.java
index 3bf7adc..525b755 100644
--- a/src/com/nullwire/trace/ExceptionClickListener.java
+++ b/src/com/nullwire/trace/ExceptionClickListener.java
@@ -30,7 +30,7 @@ public class ExceptionClickListener implements OnClickListener {
public void run() {
ExceptionHandler.submitStackTraces();
}
- }).run();
+ }).start();
break;
case DialogInterface.BUTTON_NEGATIVE:
dialog.dismiss();
@@ -39,7 +39,7 @@ public class ExceptionClickListener implements OnClickListener {
public void run() {
ExceptionHandler.removeStackTraces();
}
- }).run();
+ }).start();
break;
default:
Log.d("ExceptionClickListener", "Got unknown button click: " + whichButton);
diff --git a/src/com/trilead/ssh2/channel/DynamicAcceptThread.java b/src/com/trilead/ssh2/channel/DynamicAcceptThread.java
index f3c8b07..ef3a3d0 100644
--- a/src/com/trilead/ssh2/channel/DynamicAcceptThread.java
+++ b/src/com/trilead/ssh2/channel/DynamicAcceptThread.java
@@ -202,7 +202,7 @@ public class DynamicAcceptThread extends Thread implements IChannelWorkerThread
}
try {
- r2l = new StreamForwarder(cn, null, null, cn.stdoutStream, out, "RemoteToLocal");
+ r2l = new StreamForwarder(cn, null, sock, cn.stdoutStream, out, "RemoteToLocal");
l2r = new StreamForwarder(cn, r2l, sock, in, cn.stdinStream, "LocalToRemote");
} catch (IOException e) {
try {
diff --git a/src/com/trilead/ssh2/channel/LocalAcceptThread.java b/src/com/trilead/ssh2/channel/LocalAcceptThread.java
index 1b08d9c..885b41f 100644
--- a/src/com/trilead/ssh2/channel/LocalAcceptThread.java
+++ b/src/com/trilead/ssh2/channel/LocalAcceptThread.java
@@ -96,7 +96,7 @@ public class LocalAcceptThread extends Thread implements IChannelWorkerThread
try
{
- r2l = new StreamForwarder(cn, null, null, cn.stdoutStream, s.getOutputStream(), "RemoteToLocal");
+ r2l = new StreamForwarder(cn, null, s, cn.stdoutStream, s.getOutputStream(), "RemoteToLocal");
l2r = new StreamForwarder(cn, r2l, s, s.getInputStream(), cn.stdinStream, "LocalToRemote");
}
catch (IOException e)
diff --git a/src/com/trilead/ssh2/channel/RemoteAcceptThread.java b/src/com/trilead/ssh2/channel/RemoteAcceptThread.java
index 1ca9d76..8b97b55 100644
--- a/src/com/trilead/ssh2/channel/RemoteAcceptThread.java
+++ b/src/com/trilead/ssh2/channel/RemoteAcceptThread.java
@@ -52,7 +52,7 @@ public class RemoteAcceptThread extends Thread
s = new Socket(targetAddress, targetPort);
- StreamForwarder r2l = new StreamForwarder(c, null, null, c.getStdoutStream(), s.getOutputStream(),
+ StreamForwarder r2l = new StreamForwarder(c, null, s, c.getStdoutStream(), s.getOutputStream(),
"RemoteToLocal");
StreamForwarder l2r = new StreamForwarder(c, null, null, s.getInputStream(), c.getStdinStream(),
"LocalToRemote");
diff --git a/src/com/trilead/ssh2/channel/RemoteX11AcceptThread.java b/src/com/trilead/ssh2/channel/RemoteX11AcceptThread.java
index 8ee05a2..34ce51f 100644
--- a/src/com/trilead/ssh2/channel/RemoteX11AcceptThread.java
+++ b/src/com/trilead/ssh2/channel/RemoteX11AcceptThread.java
@@ -191,7 +191,7 @@ public class RemoteX11AcceptThread extends Thread
/* Start forwarding traffic */
- StreamForwarder r2l = new StreamForwarder(c, null, null, remote_is, x11_os, "RemoteToX11");
+ StreamForwarder r2l = new StreamForwarder(c, null, s, remote_is, x11_os, "RemoteToX11");
StreamForwarder l2r = new StreamForwarder(c, null, null, x11_is, remote_os, "X11ToRemote");
/* No need to start two threads, one can be executed in the current thread */
diff --git a/src/com/trilead/ssh2/channel/StreamForwarder.java b/src/com/trilead/ssh2/channel/StreamForwarder.java
index 376a3a0..7e54efb 100644
--- a/src/com/trilead/ssh2/channel/StreamForwarder.java
+++ b/src/com/trilead/ssh2/channel/StreamForwarder.java
@@ -17,13 +17,13 @@ import java.net.Socket;
*/
public class StreamForwarder extends Thread
{
- OutputStream os;
- InputStream is;
- byte[] buffer = new byte[Channel.CHANNEL_BUFFER_SIZE];
- Channel c;
- StreamForwarder sibling;
- Socket s;
- String mode;
+ final OutputStream os;
+ final InputStream is;
+ final byte[] buffer = new byte[Channel.CHANNEL_BUFFER_SIZE];
+ final Channel c;
+ final StreamForwarder sibling;
+ final Socket s;
+ final String mode;
StreamForwarder(Channel c, StreamForwarder sibling, Socket s, InputStream is, OutputStream os, String mode)
throws IOException
@@ -97,11 +97,12 @@ public class StreamForwarder extends Thread
catch (IOException e3)
{
}
+ }
+ if (s != null) {
try
{
- if (s != null)
- s.close();
+ s.close();
}
catch (IOException e1)
{
@@ -109,4 +110,4 @@ public class StreamForwarder extends Thread
}
}
}
-} \ No newline at end of file
+}
diff --git a/src/com/trilead/ssh2/compression/CompressionFactory.java b/src/com/trilead/ssh2/compression/CompressionFactory.java
index a846f58..9f8d7ef 100644
--- a/src/com/trilead/ssh2/compression/CompressionFactory.java
+++ b/src/com/trilead/ssh2/compression/CompressionFactory.java
@@ -43,7 +43,7 @@ public class CompressionFactory {
/* Higher Priority First */
compressors.addElement(new CompressorEntry("zlib", "com.trilead.ssh2.compression.Zlib"));
- compressors.addElement(new CompressorEntry("zlib@openssh.com", "com.trilead.ssh2.compression.Zlib"));
+ compressors.addElement(new CompressorEntry("zlib@openssh.com", "com.trilead.ssh2.compression.ZlibOpenSSH"));
compressors.addElement(new CompressorEntry("none", ""));
}
diff --git a/src/com/trilead/ssh2/compression/ICompressor.java b/src/com/trilead/ssh2/compression/ICompressor.java
index 3f76326..0b435b9 100644
--- a/src/com/trilead/ssh2/compression/ICompressor.java
+++ b/src/com/trilead/ssh2/compression/ICompressor.java
@@ -27,4 +27,6 @@ public interface ICompressor {
int compress(byte[] buf, int start, int len, byte[] output);
byte[] uncompress(byte[] buf, int start, int[] len);
+
+ boolean canCompressPreauth();
}
diff --git a/src/com/trilead/ssh2/compression/Zlib.java b/src/com/trilead/ssh2/compression/Zlib.java
index e9cc017..c1203a3 100644
--- a/src/com/trilead/ssh2/compression/Zlib.java
+++ b/src/com/trilead/ssh2/compression/Zlib.java
@@ -47,6 +47,10 @@ public class Zlib implements ICompressor {
inflated_buf = new byte[DEFAULT_BUF_SIZE];
}
+ public boolean canCompressPreauth() {
+ return true;
+ }
+
public int getBufferSize() {
return DEFAULT_BUF_SIZE;
}
diff --git a/src/com/trilead/ssh2/compression/ZlibOpenSSH.java b/src/com/trilead/ssh2/compression/ZlibOpenSSH.java
new file mode 100644
index 0000000..266fff9
--- /dev/null
+++ b/src/com/trilead/ssh2/compression/ZlibOpenSSH.java
@@ -0,0 +1,35 @@
+/*
+ * ConnectBot: simple, powerful, open-source SSH client for Android
+ * Copyright 2007 Kenny Root, Jeffrey Sharkey
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.trilead.ssh2.compression;
+
+/**
+ * Defines how zlib@openssh.org compression works.
+ * See
+ * http://www.openssh.org/txt/draft-miller-secsh-compression-delayed-00.txt
+ * compression is disabled until userauth has occurred.
+ *
+ * @author Matt Johnston
+ *
+ */
+public class ZlibOpenSSH extends Zlib {
+
+ public boolean canCompressPreauth() {
+ return false;
+ }
+
+}
diff --git a/src/com/trilead/ssh2/transport/TransportConnection.java b/src/com/trilead/ssh2/transport/TransportConnection.java
index 77eaded..2c04ce4 100644
--- a/src/com/trilead/ssh2/transport/TransportConnection.java
+++ b/src/com/trilead/ssh2/transport/TransportConnection.java
@@ -56,7 +56,9 @@ public class TransportConnection
ICompressor send_comp = null;
- boolean can_compress = false;
+ boolean can_recv_compress = false;
+
+ boolean can_send_compress = false;
byte[] recv_comp_buffer;
@@ -117,16 +119,20 @@ public class TransportConnection
{
recv_comp = comp;
- if (comp != null)
+ if (comp != null) {
recv_comp_buffer = new byte[comp.getBufferSize()];
+ can_recv_compress |= recv_comp.canCompressPreauth();
+ }
}
public void changeSendCompression(ICompressor comp)
{
send_comp = comp;
- if (comp != null)
+ if (comp != null) {
send_comp_buffer = new byte[comp.getBufferSize()];
+ can_send_compress |= send_comp.canCompressPreauth();
+ }
}
public void sendMessage(byte[] message) throws IOException
@@ -152,7 +158,7 @@ public class TransportConnection
else if (padd > 64)
padd = 64;
- if (send_comp != null && can_compress) {
+ if (send_comp != null && can_send_compress) {
if (send_comp_buffer.length < message.length + 1024)
send_comp_buffer = new byte[message.length + 1024];
len = send_comp.compress(message, off, len, send_comp_buffer);
@@ -313,7 +319,7 @@ public class TransportConnection
+ " bytes payload");
}
- if (recv_comp != null && can_compress) {
+ if (recv_comp != null && can_recv_compress) {
int[] uncomp_len = new int[] { payload_length };
buffer = recv_comp.uncompress(buffer, off, uncomp_len);
@@ -331,6 +337,7 @@ public class TransportConnection
*
*/
public void startCompression() {
- can_compress = true;
+ can_recv_compress = true;
+ can_send_compress = true;
}
}
diff --git a/src/de/mud/terminal/vt320.java b/src/de/mud/terminal/vt320.java
index fd41a06..80f3856 100644
--- a/src/de/mud/terminal/vt320.java
+++ b/src/de/mud/terminal/vt320.java
@@ -25,6 +25,8 @@
package de.mud.terminal;
+import android.text.AndroidCharacter;
+
import java.util.Properties;
/**
@@ -111,8 +113,11 @@ public abstract class vt320 extends VDUBuffer implements VDUInput {
if (lastChar != -1)
putChar((char) lastChar, isWide, false);
lastChar = c;
- if (fullwidths != null)
- isWide = fullwidths[i] == 1;
+ if (fullwidths != null) {
+ final byte width = fullwidths[i];
+ isWide = (width == AndroidCharacter.EAST_ASIAN_WIDTH_WIDE)
+ || (width == AndroidCharacter.EAST_ASIAN_WIDTH_FULL_WIDTH);
+ }
}
}
}
diff --git a/src/org/connectbot/ConsoleActivity.java b/src/org/connectbot/ConsoleActivity.java
index 0240131..31ba444 100644
--- a/src/org/connectbot/ConsoleActivity.java
+++ b/src/org/connectbot/ConsoleActivity.java
@@ -23,6 +23,7 @@ import java.util.List;
import org.connectbot.bean.SelectionArea;
import org.connectbot.service.PromptHelper;
import org.connectbot.service.TerminalBridge;
+import org.connectbot.service.TerminalKeyListener;
import org.connectbot.service.TerminalManager;
import org.connectbot.util.PreferenceConstants;
@@ -43,7 +44,6 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
-import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.text.ClipboardManager;
import android.util.Log;
@@ -84,9 +84,9 @@ public class ConsoleActivity extends Activity {
protected static final int REQUEST_EDIT = 1;
- private static final int CLICK_TIME = 250;
+ private static final int CLICK_TIME = 400;
private static final float MAX_CLICK_DISTANCE = 25f;
- private static final int KEYBOARD_DISPLAY_TIME = 1250;
+ private static final int KEYBOARD_DISPLAY_TIME = 1500;
// Direction to shift the ViewFlipper
private static final int SHIFT_LEFT = 0;
@@ -98,7 +98,9 @@ public class ConsoleActivity extends Activity {
private SharedPreferences prefs = null;
- private PowerManager.WakeLock wakelock = null;
+ // determines whether or not menuitem accelerators are bound
+ // otherwise they collide with an external keyboard's CTRL-char
+ private boolean hardKeyboard = false;
protected Uri requested;
@@ -116,7 +118,6 @@ public class ConsoleActivity extends Activity {
private Animation slide_left_in, slide_left_out, slide_right_in, slide_right_out, fade_stay_hidden, fade_out_delayed;
private Animation keyboard_fade_in, keyboard_fade_out;
- private ImageView keyboardButton;
private float lastX, lastY;
private InputMethodManager inputManager;
@@ -130,6 +131,8 @@ public class ConsoleActivity extends Activity {
private Handler handler = new Handler();
+ private ImageView mKeyboardButton;
+
private ServiceConnection connection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
bound = ((TerminalManager.TerminalBinder) service).getService();
@@ -256,9 +259,20 @@ public class ConsoleActivity extends Activity {
booleanPromptGroup.setVisibility(View.GONE);
}
+ // more like configureLaxMode -- enable network IO on UI thread
+ private void configureStrictMode() {
+ try {
+ Class.forName("android.os.StrictMode");
+ StrictModeSetup.run();
+ } catch (ClassNotFoundException e) {
+ }
+ }
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
+ configureStrictMode();
+ hardKeyboard = getResources().getConfiguration().keyboard ==
+ Configuration.KEYBOARD_QWERTY;
this.setContentView(R.layout.act_console);
@@ -276,9 +290,6 @@ public class ConsoleActivity extends Activity {
// TODO find proper way to disable volume key beep if it exists.
setVolumeControlStream(AudioManager.STREAM_MUSIC);
- PowerManager manager = (PowerManager)getSystemService(Context.POWER_SERVICE);
- wakelock = manager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, TAG);
-
// handle requested console from incoming intent
requested = getIntent().getData();
@@ -347,15 +358,46 @@ public class ConsoleActivity extends Activity {
keyboard_fade_out = AnimationUtils.loadAnimation(this, R.anim.keyboard_fade_out);
inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
- keyboardButton = (ImageView) findViewById(R.id.keyboard_button);
- keyboardButton.setOnClickListener(new OnClickListener() {
+
+ final RelativeLayout keyboardGroup = (RelativeLayout) findViewById(R.id.keyboard_group);
+
+ mKeyboardButton = (ImageView) findViewById(R.id.button_keyboard);
+ mKeyboardButton.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
View flip = findCurrentView(R.id.console_flip);
if (flip == null)
return;
inputManager.showSoftInput(flip, InputMethodManager.SHOW_FORCED);
- keyboardButton.setVisibility(View.GONE);
+ keyboardGroup.setVisibility(View.GONE);
+ }
+ });
+
+ final ImageView ctrlButton = (ImageView) findViewById(R.id.button_ctrl);
+ ctrlButton.setOnClickListener(new OnClickListener() {
+ public void onClick(View view) {
+ View flip = findCurrentView(R.id.console_flip);
+ if (flip == null) return;
+ TerminalView terminal = (TerminalView)flip;
+
+ TerminalKeyListener handler = terminal.bridge.getKeyHandler();
+ handler.metaPress(TerminalKeyListener.META_CTRL_ON);
+
+ keyboardGroup.setVisibility(View.GONE);
+ }
+ });
+
+ final ImageView escButton = (ImageView) findViewById(R.id.button_esc);
+ escButton.setOnClickListener(new OnClickListener() {
+ public void onClick(View view) {
+ View flip = findCurrentView(R.id.console_flip);
+ if (flip == null) return;
+ TerminalView terminal = (TerminalView)flip;
+
+ TerminalKeyListener handler = terminal.bridge.getKeyHandler();
+ handler.sendEscape();
+
+ keyboardGroup.setVisibility(View.GONE);
}
});
@@ -519,21 +561,20 @@ public class ConsoleActivity extends Activity {
lastX = event.getX();
lastY = event.getY();
} else if (event.getAction() == MotionEvent.ACTION_UP
- && config.hardKeyboardHidden != Configuration.KEYBOARDHIDDEN_NO
- && keyboardButton.getVisibility() == View.GONE
+ && keyboardGroup.getVisibility() == View.GONE
&& event.getEventTime() - event.getDownTime() < CLICK_TIME
&& Math.abs(event.getX() - lastX) < MAX_CLICK_DISTANCE
&& Math.abs(event.getY() - lastY) < MAX_CLICK_DISTANCE) {
- keyboardButton.startAnimation(keyboard_fade_in);
- keyboardButton.setVisibility(View.VISIBLE);
+ keyboardGroup.startAnimation(keyboard_fade_in);
+ keyboardGroup.setVisibility(View.VISIBLE);
handler.postDelayed(new Runnable() {
public void run() {
- if (keyboardButton.getVisibility() == View.GONE)
+ if (keyboardGroup.getVisibility() == View.GONE)
return;
- keyboardButton.startAnimation(keyboard_fade_out);
- keyboardButton.setVisibility(View.GONE);
+ keyboardGroup.startAnimation(keyboard_fade_out);
+ keyboardGroup.setVisibility(View.GONE);
}
}, KEYBOARD_DISPLAY_TIME);
}
@@ -594,7 +635,8 @@ public class ConsoleActivity extends Activity {
menu.setQwertyMode(true);
disconnect = menu.add(R.string.list_host_disconnect);
- disconnect.setAlphabeticShortcut('w');
+ if (hardKeyboard)
+ disconnect.setAlphabeticShortcut('w');
if (!sessionOpen && disconnected)
disconnect.setTitle(R.string.console_menu_close);
disconnect.setEnabled(activeTerminal);
@@ -611,7 +653,8 @@ public class ConsoleActivity extends Activity {
});
copy = menu.add(R.string.console_menu_copy);
- copy.setAlphabeticShortcut('c');
+ if (hardKeyboard)
+ copy.setAlphabeticShortcut('c');
copy.setIcon(android.R.drawable.ic_menu_set_as);
copy.setEnabled(activeTerminal);
copy.setOnMenuItemClickListener(new OnMenuItemClickListener() {
@@ -635,7 +678,8 @@ public class ConsoleActivity extends Activity {
});
paste = menu.add(R.string.console_menu_paste);
- paste.setAlphabeticShortcut('v');
+ if (hardKeyboard)
+ paste.setAlphabeticShortcut('v');
paste.setIcon(android.R.drawable.ic_menu_edit);
paste.setEnabled(clipboard.hasText() && sessionOpen);
paste.setOnMenuItemClickListener(new OnMenuItemClickListener() {
@@ -653,7 +697,8 @@ public class ConsoleActivity extends Activity {
});
portForward = menu.add(R.string.console_menu_portforwards);
- portForward.setAlphabeticShortcut('f');
+ if (hardKeyboard)
+ portForward.setAlphabeticShortcut('f');
portForward.setIcon(android.R.drawable.ic_menu_manage);
portForward.setEnabled(sessionOpen && canForwardPorts);
portForward.setOnMenuItemClickListener(new OnMenuItemClickListener() {
@@ -669,7 +714,8 @@ public class ConsoleActivity extends Activity {
});
urlscan = menu.add(R.string.console_menu_urlscan);
- urlscan.setAlphabeticShortcut('u');
+ if (hardKeyboard)
+ urlscan.setAlphabeticShortcut('u');
urlscan.setIcon(android.R.drawable.ic_menu_search);
urlscan.setEnabled(activeTerminal);
urlscan.setOnMenuItemClickListener(new OnMenuItemClickListener() {
@@ -694,7 +740,8 @@ public class ConsoleActivity extends Activity {
});
resize = menu.add(R.string.console_menu_resize);
- resize.setAlphabeticShortcut('s');
+ if (hardKeyboard)
+ resize.setAlphabeticShortcut('s');
resize.setIcon(android.R.drawable.ic_menu_crop);
resize.setEnabled(sessionOpen);
resize.setOnMenuItemClickListener(new OnMenuItemClickListener() {
@@ -785,10 +832,6 @@ public class ConsoleActivity extends Activity {
super.onPause();
Log.d(TAG, "onPause called");
- // Allow the screen to dim and fall asleep.
- if (wakelock != null && wakelock.isHeld())
- wakelock.release();
-
if (forcedOrientation && bound != null)
bound.setResizeAllowed(false);
}
@@ -800,8 +843,11 @@ public class ConsoleActivity extends Activity {
// Make sure we don't let the screen fall asleep.
// This also keeps the Wi-Fi chipset from disconnecting us.
- if (wakelock != null && prefs.getBoolean(PreferenceConstants.KEEP_ALIVE, true))
- wakelock.acquire();
+ if (prefs.getBoolean(PreferenceConstants.KEEP_ALIVE, true)) {
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ } else {
+ getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ }
configureOrientation();
@@ -843,6 +889,8 @@ public class ConsoleActivity extends Activity {
requestedBridge = bound.openConnection(requested);
} catch(Exception e) {
Log.e(TAG, "Problem while trying to create new requested bridge from URI", e);
+ // TODO: We should display an error dialog here.
+ return;
}
requestedIndex = addNewTerminalView(requestedBridge);
@@ -1006,6 +1054,8 @@ public class ConsoleActivity extends Activity {
bound.setResizeAllowed(true);
bound.hardKeyboardHidden = (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES);
+
+ mKeyboardButton.setVisibility(bound.hardKeyboardHidden ? View.VISIBLE : View.GONE);
}
}
diff --git a/src/org/connectbot/HostEditorActivity.java b/src/org/connectbot/HostEditorActivity.java
index 95d04cc..4e8427f 100644
--- a/src/org/connectbot/HostEditorActivity.java
+++ b/src/org/connectbot/HostEditorActivity.java
@@ -23,6 +23,7 @@ import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.Map.Entry;
import org.connectbot.bean.HostBean;
@@ -130,6 +131,11 @@ public class HostEditorActivity extends PreferenceActivity implements OnSharedPr
return true;
}
+ // Gingerbread compatibility
+ public void apply() {
+ commit();
+ }
+
public android.content.SharedPreferences.Editor putBoolean(String key, boolean value) {
return this.putString(key, Boolean.toString(value));
}
@@ -158,6 +164,9 @@ public class HostEditorActivity extends PreferenceActivity implements OnSharedPr
return this;
}
+ public android.content.SharedPreferences.Editor putStringSet(String key, Set<String> value) {
+ throw new UnsupportedOperationException("HostEditor Prefs do not support Set<String>");
+ }
}
@@ -193,6 +202,10 @@ public class HostEditorActivity extends PreferenceActivity implements OnSharedPr
return values.get(key);
}
+ public Set<String> getStringSet(String key, Set<String> defValue) {
+ throw new ClassCastException("HostEditor Prefs do not support Set<String>");
+ }
+
protected List<OnSharedPreferenceChangeListener> listeners = new LinkedList<OnSharedPreferenceChangeListener>();
public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
diff --git a/src/org/connectbot/HostListActivity.java b/src/org/connectbot/HostListActivity.java
index f65c069..3b02530 100644
--- a/src/org/connectbot/HostListActivity.java
+++ b/src/org/connectbot/HostListActivity.java
@@ -178,7 +178,8 @@ public class HostListActivity extends ListActivity {
// start thread to check for new version
new UpdateHelper(this);
- this.makingShortcut = Intent.ACTION_CREATE_SHORTCUT.equals(getIntent().getAction());
+ this.makingShortcut = Intent.ACTION_CREATE_SHORTCUT.equals(getIntent().getAction())
+ || Intent.ACTION_PICK.equals(getIntent().getAction());
// connect with hosts database and populate list
this.hostdb = new HostDatabase(this);
diff --git a/src/org/connectbot/PortForwardListActivity.java b/src/org/connectbot/PortForwardListActivity.java
index e5c6d21..f9982e4 100644
--- a/src/org/connectbot/PortForwardListActivity.java
+++ b/src/org/connectbot/PortForwardListActivity.java
@@ -113,7 +113,7 @@ public class PortForwardListActivity extends ListActivity {
host = hostdb.findHostById(hostId);
{
- String nickname = host.getNickname();
+ final String nickname = host != null ? host.getNickname() : null;
final Resources resources = getResources();
if (nickname != null) {
@@ -209,7 +209,8 @@ public class PortForwardListActivity extends ListActivity {
break;
}
- PortForwardBean pfb = new PortForwardBean(host.getId(),
+ PortForwardBean pfb = new PortForwardBean(
+ host != null ? host.getId() : -1,
nicknameEdit.getText().toString(), type,
sourcePortEdit.getText().toString(),
destEdit.getText().toString());
@@ -219,7 +220,7 @@ public class PortForwardListActivity extends ListActivity {
hostBridge.enablePortForward(pfb);
}
- if (!hostdb.savePortForward(pfb))
+ if (host != null && !hostdb.savePortForward(pfb))
throw new SQLException("Could not save port forward");
updateHandler.sendEmptyMessage(-1);
diff --git a/src/org/connectbot/PubkeyListActivity.java b/src/org/connectbot/PubkeyListActivity.java
index 9106e1a..3579980 100644
--- a/src/org/connectbot/PubkeyListActivity.java
+++ b/src/org/connectbot/PubkeyListActivity.java
@@ -293,7 +293,7 @@ public class PubkeyListActivity extends ListActivity implements EventListener {
Log.d(TAG, String.format("Unlocked key '%s'", pubkey.getNickname()));
// save this key in memory
- bound.addKey(pubkey, trileadKey);
+ bound.addKey(pubkey, trileadKey, true);
updateHandler.sendEmptyMessage(-1);
}
diff --git a/src/org/connectbot/StrictModeSetup.java b/src/org/connectbot/StrictModeSetup.java
new file mode 100644
index 0000000..3a2000e
--- /dev/null
+++ b/src/org/connectbot/StrictModeSetup.java
@@ -0,0 +1,23 @@
+/*
+ * ConnectBot: simple, powerful, open-source SSH client for Android
+ * Copyright 2007 Kenny Root, Jeffrey Sharkey
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.connectbot;
+import android.os.StrictMode;
+public class StrictModeSetup {
+ public static void run() {
+ StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.LAX);
+ }
+}
diff --git a/src/org/connectbot/TerminalView.java b/src/org/connectbot/TerminalView.java
index 45f2977..e2f257c 100755
--- a/src/org/connectbot/TerminalView.java
+++ b/src/org/connectbot/TerminalView.java
@@ -39,6 +39,7 @@ import android.graphics.Path;
import android.graphics.PixelXorXfermode;
import android.graphics.RectF;
import android.net.Uri;
+import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.accessibility.AccessibilityEvent;
@@ -203,6 +204,11 @@ public class TerminalView extends View implements FontSizeChangedListener {
bridge.charHeight);
canvas.drawPaint(cursorPaint);
+ final int deadKey = bridge.getKeyHandler().getDeadKey();
+ if (deadKey != 0) {
+ canvas.drawText(new char[] { (char)deadKey }, 0, 1, 0, 0, cursorStrokePaint);
+ }
+
// Make sure we scale our decorations to the correct size.
canvas.concat(scaleMatrix);
@@ -291,7 +297,19 @@ public class TerminalView extends View implements FontSizeChangedListener {
EditorInfo.IME_FLAG_NO_ENTER_ACTION |
EditorInfo.IME_ACTION_NONE;
outAttrs.inputType = EditorInfo.TYPE_NULL;
- return new BaseInputConnection(this, false);
+ return new BaseInputConnection(this, false) {
+ @Override
+ public boolean deleteSurroundingText (int leftLength, int rightLength) {
+ if (rightLength == 0 && leftLength == 0) {
+ return this.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL));
+ }
+ for (int i = 0; i < leftLength; i++) {
+ this.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL));
+ }
+ // TODO: forward delete
+ return true;
+ }
+ };
}
public StringBuffer getAccessibilityBuffer() {
diff --git a/src/org/connectbot/service/ConnectionNotifier.java b/src/org/connectbot/service/ConnectionNotifier.java
index 679ed9e..d276761 100644
--- a/src/org/connectbot/service/ConnectionNotifier.java
+++ b/src/org/connectbot/service/ConnectionNotifier.java
@@ -17,6 +17,9 @@
package org.connectbot.service;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
import org.connectbot.ConsoleActivity;
import org.connectbot.R;
import org.connectbot.bean.HostBean;
@@ -41,7 +44,7 @@ public abstract class ConnectionNotifier {
private static final int ONLINE_NOTIFICATION = 1;
private static final int ACTIVITY_NOTIFICATION = 2;
- public static ConnectionNotifier getInstance() {
+ public static ConnectionNotifier getInstance() {
if (PreferenceConstants.PRE_ECLAIR)
return PreEclair.Holder.sInstance;
else
@@ -128,20 +131,46 @@ public abstract class ConnectionNotifier {
public abstract void hideRunningNotification(Service context);
private static class PreEclair extends ConnectionNotifier {
+ private static final Class<?>[] setForegroundSignature = new Class[] {boolean.class};
+ private Method setForeground = null;
+
private static class Holder {
private static final PreEclair sInstance = new PreEclair();
}
+ public PreEclair() {
+ try {
+ setForeground = Service.class.getMethod("setForeground", setForegroundSignature);
+ } catch (Exception e) {
+ }
+ }
+
@Override
public void showRunningNotification(Service context) {
- context.setForeground(true);
- getNotificationManager(context).notify(ONLINE_NOTIFICATION, newRunningNotification(context));
+ if (setForeground != null) {
+ Object[] setForegroundArgs = new Object[1];
+ setForegroundArgs[0] = Boolean.TRUE;
+ try {
+ setForeground.invoke(context, setForegroundArgs);
+ } catch (InvocationTargetException e) {
+ } catch (IllegalAccessException e) {
+ }
+ getNotificationManager(context).notify(ONLINE_NOTIFICATION, newRunningNotification(context));
+ }
}
@Override
public void hideRunningNotification(Service context) {
- context.setForeground(false);
- getNotificationManager(context).cancel(ONLINE_NOTIFICATION);
+ if (setForeground != null) {
+ Object[] setForegroundArgs = new Object[1];
+ setForegroundArgs[0] = Boolean.FALSE;
+ try {
+ setForeground.invoke(context, setForegroundArgs);
+ } catch (InvocationTargetException e) {
+ } catch (IllegalAccessException e) {
+ }
+ getNotificationManager(context).cancel(ONLINE_NOTIFICATION);
+ }
}
}
diff --git a/src/org/connectbot/service/ConnectivityReceiver.java b/src/org/connectbot/service/ConnectivityReceiver.java
index e2d2d3b..3248a2a 100644
--- a/src/org/connectbot/service/ConnectivityReceiver.java
+++ b/src/org/connectbot/service/ConnectivityReceiver.java
@@ -31,6 +31,8 @@ public class ConnectivityReceiver extends BroadcastReceiver {
private boolean mLockingWifi;
+ private Object[] mLock = new Object[0];
+
public ConnectivityReceiver(TerminalManager manager, boolean lockingWifi) {
mTerminalManager = manager;
@@ -93,21 +95,26 @@ public class ConnectivityReceiver extends BroadcastReceiver {
}
/**
- * Increase the number of things using the network. Acquire a Wifi lock if necessary.
+ * Increase the number of things using the network. Acquire a Wi-Fi lock
+ * if necessary.
*/
public void incRef() {
- synchronized (this) {
- acquireWifiLockIfNecessary();
-
+ synchronized (mLock) {
mNetworkRef += 1;
+
+ acquireWifiLockIfNecessaryLocked();
}
}
+ /**
+ * Decrease the number of things using the network. Release the Wi-Fi lock
+ * if necessary.
+ */
public void decRef() {
- synchronized (this) {
+ synchronized (mLock) {
mNetworkRef -= 1;
- releaseWifiLockIfNecessary();
+ releaseWifiLockIfNecessaryLocked();
}
}
@@ -115,32 +122,24 @@ public class ConnectivityReceiver extends BroadcastReceiver {
* @param mLockingWifi
*/
public void setWantWifiLock(boolean lockingWifi) {
- synchronized (this) {
+ synchronized (mLock) {
mLockingWifi = lockingWifi;
if (mLockingWifi) {
- acquireWifiLockIfNecessary();
- } else if (!mLockingWifi) {
- releaseWifiLockIfNecessary();
+ acquireWifiLockIfNecessaryLocked();
+ } else {
+ releaseWifiLockIfNecessaryLocked();
}
}
}
- /**
- *
- */
- private void acquireWifiLockIfNecessary() {
- synchronized (this) {
- if (mLockingWifi && mNetworkRef > 0 && !mWifiLock.isHeld()) {
- mWifiLock.acquire();
- }
+ private void acquireWifiLockIfNecessaryLocked() {
+ if (mLockingWifi && mNetworkRef > 0 && !mWifiLock.isHeld()) {
+ mWifiLock.acquire();
}
}
- /**
- *
- */
- private void releaseWifiLockIfNecessary() {
+ private void releaseWifiLockIfNecessaryLocked() {
if (mNetworkRef == 0 && mWifiLock.isHeld()) {
mWifiLock.release();
}
diff --git a/src/org/connectbot/service/Relay.java b/src/org/connectbot/service/Relay.java
index f14ff53..36672ec 100644
--- a/src/org/connectbot/service/Relay.java
+++ b/src/org/connectbot/service/Relay.java
@@ -40,13 +40,10 @@ public class Relay implements Runnable {
private static final int BUFFER_SIZE = 4096;
- private static boolean useJNI = true;
-
private TerminalBridge bridge;
private Charset currentCharset;
private CharsetDecoder decoder;
- private boolean isLegacyEastAsian = false;
private AbsTransport transport;
@@ -58,10 +55,6 @@ public class Relay implements Runnable {
private byte[] byteArray;
private char[] charArray;
- static {
- useJNI = EastAsianWidth.useJNI;
- }
-
public Relay(TerminalBridge bridge, AbsTransport transport, vt320 buffer, String encoding) {
setCharset(encoding);
this.bridge = bridge;
@@ -99,16 +92,9 @@ public class Relay implements Runnable {
byteBuffer = ByteBuffer.allocate(BUFFER_SIZE);
charBuffer = CharBuffer.allocate(BUFFER_SIZE);
- /* for both JNI and non-JNI method */
+ /* for East Asian character widths */
byte[] wideAttribute = new byte[BUFFER_SIZE];
- /* non-JNI fallback method */
- float[] widths = null;
-
- if (!useJNI) {
- widths = new float[BUFFER_SIZE];
- }
-
byteArray = byteBuffer.array();
charArray = charBuffer.array();
@@ -120,6 +106,8 @@ public class Relay implements Runnable {
int offset;
int charWidth;
+ EastAsianWidth measurer = EastAsianWidth.getInstance();
+
try {
while (true) {
charWidth = bridge.charWidth;
@@ -143,15 +131,7 @@ public class Relay implements Runnable {
offset = charBuffer.position();
- if (!useJNI) {
- bridge.defaultPaint.getTextWidths(charArray, 0, offset, widths);
- for (int i = 0; i < offset; i++)
- wideAttribute[i] =
- (byte) (((int)widths[i] != charWidth) ? 1 : 0);
- } else {
- EastAsianWidth.measure(charArray, 0, charBuffer.position(),
- wideAttribute, isLegacyEastAsian);
- }
+ measurer.measure(charArray, 0, offset, wideAttribute, bridge.defaultPaint, charWidth);
buffer.putString(charArray, wideAttribute, 0, charBuffer.position());
bridge.propagateConsoleText(charArray, charBuffer.position());
charBuffer.clear();
diff --git a/src/org/connectbot/service/TerminalBridge.java b/src/org/connectbot/service/TerminalBridge.java
index 9b4b96c..f25ba5d 100644
--- a/src/org/connectbot/service/TerminalBridge.java
+++ b/src/org/connectbot/service/TerminalBridge.java
@@ -57,6 +57,7 @@ import de.mud.terminal.vt320;
* This class also provides SSH hostkey verification prompting, and password
* prompting.
*/
+@SuppressWarnings("deprecation") // for ClipboardManager
public class TerminalBridge implements VDUDisplay {
public final static String TAG = "ConnectBot.TerminalBridge";
@@ -98,6 +99,8 @@ public class TerminalBridge implements VDUDisplay {
private boolean selectingForCopy = false;
private final SelectionArea selectionArea;
+
+ // TODO add support for the new clipboard API
private ClipboardManager clipboard;
public int charWidth = -1;
@@ -921,8 +924,6 @@ public class TerminalBridge implements VDUDisplay {
color = manager.hostdb.getColorsForScheme(HostDatabase.DEFAULT_COLOR_SCHEME);
}
- // This was taken from http://geekswithblogs.net/casualjim/archive/2005/12/01/61722.aspx
- private final static String urlRegex = "(?:(?:ht|f)tp(?:s?)\\:\\/\\/|~/|/)?(?:\\w+:\\w+@)?(?:(?:[-\\w]+\\.)+(?:com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|museum|travel|[a-z]{2}))(?::[\\d]{1,5})?(?:(?:(?:/(?:[-\\w~!$+|.,=]|%[a-f\\d]{2})+)+|/)+|\\?|#)?(?:(?:\\?(?:[-\\w~!$+|.,*:]|%[a-f\\d{2}])+=(?:[-\\w~!$+|.,*:=]|%[a-f\\d]{2})*)(?:&(?:[-\\w~!$+|.,*:]|%[a-f\\d{2}])+=(?:[-\\w~!$+|.,*:=]|%[a-f\\d]{2})*)*)*(?:#(?:[-\\w~!$+|.,*:=]|%[a-f\\d]{2})*)?";
private static Pattern urlPattern = null;
/**
@@ -931,8 +932,36 @@ public class TerminalBridge implements VDUDisplay {
public List<String> scanForURLs() {
List<String> urls = new LinkedList<String>();
- if (urlPattern == null)
- urlPattern = Pattern.compile(urlRegex);
+ if (urlPattern == null) {
+ // based on http://www.ietf.org/rfc/rfc2396.txt
+ String scheme = "[A-Za-z][-+.0-9A-Za-z]*";
+ String unreserved = "[-._~0-9A-Za-z]";
+ String pctEncoded = "%[0-9A-Fa-f]{2}";
+ String subDelims = "[!$&'()*+,;:=]";
+ String userinfo = "(?:" + unreserved + "|" + pctEncoded + "|" + subDelims + "|:)*";
+ String h16 = "[0-9A-Fa-f]{1,4}";
+ String decOctet = "(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])";
+ String ipv4address = decOctet + "\\." + decOctet + "\\." + decOctet + "\\." + decOctet;
+ String ls32 = "(?:" + h16 + ":" + h16 + "|" + ipv4address + ")";
+ String ipv6address = "(?:(?:" + h16 + "){6}" + ls32 + ")";
+ String ipvfuture = "v[0-9A-Fa-f]+.(?:" + unreserved + "|" + subDelims + "|:)+";
+ String ipLiteral = "\\[(?:" + ipv6address + "|" + ipvfuture + ")\\]";
+ String regName = "(?:" + unreserved + "|" + pctEncoded + "|" + subDelims + ")*";
+ String host = "(?:" + ipLiteral + "|" + ipv4address + "|" + regName + ")";
+ String port = "[0-9]*";
+ String authority = "(?:" + userinfo + "@)?" + host + "(?::" + port + ")?";
+ String pchar = "(?:" + unreserved + "|" + pctEncoded + "|" + subDelims + "|@)";
+ String segment = pchar + "*";
+ String pathAbempty = "(?:/" + segment + ")*";
+ String segmentNz = pchar + "+";
+ String pathAbsolute = "/(?:" + segmentNz + "(?:/" + segment + ")*)?";
+ String pathRootless = segmentNz + "(?:/" + segment + ")*";
+ String hierPart = "(?://" + authority + pathAbempty + "|" + pathAbsolute + "|" + pathRootless + ")";
+ String query = "(?:" + pchar + "|/|\\?)*";
+ String fragment = "(?:" + pchar + "|/|\\?)*";
+ String uriRegex = scheme + ":" + hierPart + "(?:" + query + ")?(?:#" + fragment + ")?";
+ urlPattern = Pattern.compile(uriRegex);
+ }
char[] visibleBuffer = new char[buffer.height * buffer.width];
for (int l = 0; l < buffer.height; l++)
diff --git a/src/org/connectbot/service/TerminalKeyListener.java b/src/org/connectbot/service/TerminalKeyListener.java
index af752bf..952f3cd 100644
--- a/src/org/connectbot/service/TerminalKeyListener.java
+++ b/src/org/connectbot/service/TerminalKeyListener.java
@@ -1,5 +1,18 @@
-/**
+/*
+ * ConnectBot: simple, powerful, open-source SSH client for Android
+ * Copyright 2010 Kenny Root, Jeffrey Sharkey
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
*
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package org.connectbot.service;
@@ -26,6 +39,7 @@ import de.mud.terminal.vt320;
* @author kenny
*
*/
+@SuppressWarnings("deprecation") // for ClipboardManager
public class TerminalKeyListener implements OnKeyListener, OnSharedPreferenceChangeListener {
private static final String TAG = "ConnectBot.OnKeyListener";
@@ -43,6 +57,10 @@ public class TerminalKeyListener implements OnKeyListener, OnSharedPreferenceCha
public final static int META_ALT_MASK = META_ALT_ON | META_ALT_LOCK;
public final static int META_SHIFT_MASK = META_SHIFT_ON | META_SHIFT_LOCK;
+ // backport constants from api level 11
+ public final static int KEYCODE_ESCAPE = 111;
+ public final static int HC_META_CTRL_ON = 4096;
+
// All the transient key codes
public final static int META_TRANSIENT = META_CTRL_ON | META_ALT_ON
| META_SHIFT_ON;
@@ -51,14 +69,16 @@ public class TerminalKeyListener implements OnKeyListener, OnSharedPreferenceCha
private final TerminalBridge bridge;
private final VDUBuffer buffer;
- protected KeyCharacterMap keymap = KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD);
-
private String keymode = null;
private boolean hardKeyboard = false;
private int metaState = 0;
+ private int mDeadKey = 0;
+
+ // TODO add support for the new API.
private ClipboardManager clipboard = null;
+
private boolean selectingForCopy = false;
private final SelectionArea selectionArea;
@@ -148,47 +168,66 @@ public class TerminalKeyListener implements OnKeyListener, OnSharedPreferenceCha
bridge.resetScrollPosition();
- boolean printing = (keymap.isPrintingKey(keyCode) || keyCode == KeyEvent.KEYCODE_SPACE);
+ if (keyCode == KeyEvent.KEYCODE_UNKNOWN &&
+ event.getAction() == KeyEvent.ACTION_MULTIPLE) {
+ byte[] input = event.getCharacters().getBytes(encoding);
+ bridge.transport.write(input);
+ return true;
+ }
+
+ int curMetaState = event.getMetaState();
+ final int orgMetaState = curMetaState;
+
+ if ((metaState & META_SHIFT_MASK) != 0) {
+ curMetaState |= KeyEvent.META_SHIFT_ON;
+ }
+
+ if ((metaState & META_ALT_MASK) != 0) {
+ curMetaState |= KeyEvent.META_ALT_ON;
+ }
+
+ int key = event.getUnicodeChar(curMetaState);
+ // no hard keyboard? ALT-k should pass through to below
+ if ((orgMetaState & KeyEvent.META_ALT_ON) != 0 &&
+ (!hardKeyboard || hardKeyboardHidden)) {
+ key = 0;
+ }
+
+ if ((key & KeyCharacterMap.COMBINING_ACCENT) != 0) {
+ mDeadKey = key & KeyCharacterMap.COMBINING_ACCENT_MASK;
+ return true;
+ }
+
+ if (mDeadKey != 0) {
+ key = KeyCharacterMap.getDeadChar(mDeadKey, keyCode);
+ mDeadKey = 0;
+ }
+
+ final boolean printing = (key != 0);
// otherwise pass through to existing session
// print normal keys
if (printing) {
- int curMetaState = event.getMetaState();
-
metaState &= ~(META_SLASH | META_TAB);
- if ((metaState & META_SHIFT_MASK) != 0) {
- curMetaState |= KeyEvent.META_SHIFT_ON;
- metaState &= ~META_SHIFT_ON;
- bridge.redraw();
- }
-
- if ((metaState & META_ALT_MASK) != 0) {
- curMetaState |= KeyEvent.META_ALT_ON;
- metaState &= ~META_ALT_ON;
+ // Remove shift and alt modifiers
+ final int lastMetaState = metaState;
+ metaState &= ~(META_SHIFT_ON | META_ALT_ON);
+ if (metaState != lastMetaState) {
bridge.redraw();
}
- int key = keymap.get(keyCode, curMetaState);
-
if ((metaState & META_CTRL_MASK) != 0) {
metaState &= ~META_CTRL_ON;
bridge.redraw();
+ // If there is no hard keyboard or there is a hard keyboard currently hidden,
+ // CTRL-1 through CTRL-9 will send F1 through F9
if ((!hardKeyboard || (hardKeyboard && hardKeyboardHidden))
&& sendFunctionKey(keyCode))
return true;
- // Support CTRL-a through CTRL-z
- if (key >= 0x61 && key <= 0x7A)
- key -= 0x60;
- // Support CTRL-A through CTRL-_
- else if (key >= 0x41 && key <= 0x5F)
- key -= 0x40;
- else if (key == 0x20)
- key = 0x00;
- else if (key == 0x3F)
- key = 0x7F;
+ key = keyAsControl(key);
}
// handle pressing f-keys
@@ -207,13 +246,30 @@ public class TerminalKeyListener implements OnKeyListener, OnSharedPreferenceCha
return true;
}
- if (keyCode == KeyEvent.KEYCODE_UNKNOWN &&
- event.getAction() == KeyEvent.ACTION_MULTIPLE) {
- byte[] input = event.getCharacters().getBytes(encoding);
- bridge.transport.write(input);
- return true;
+ // send ctrl and meta-keys as appropriate
+ if (!hardKeyboard || hardKeyboardHidden) {
+ int k = event.getUnicodeChar(0);
+ int k0 = k;
+ boolean sendCtrl = false;
+ boolean sendMeta = false;
+ if (k != 0) {
+ if ((orgMetaState & HC_META_CTRL_ON) != 0) {
+ k = keyAsControl(k);
+ if (k != k0)
+ sendCtrl = true;
+ // send F1-F10 via CTRL-1 through CTRL-0
+ if (!sendCtrl && sendFunctionKey(keyCode))
+ return true;
+ } else if ((orgMetaState & KeyEvent.META_ALT_ON) != 0) {
+ sendMeta = true;
+ sendEscape();
+ }
+ if (sendMeta || sendCtrl) {
+ bridge.transport.write(k);
+ return true;
+ }
+ }
}
-
// try handling keymode shortcuts
if (hardKeyboard && !hardKeyboardHidden &&
event.getRepeatCount() == 0) {
@@ -263,6 +319,12 @@ public class TerminalKeyListener implements OnKeyListener, OnSharedPreferenceCha
// look for special chars
switch(keyCode) {
+ case KEYCODE_ESCAPE:
+ sendEscape();
+ return true;
+ case KeyEvent.KEYCODE_TAB:
+ bridge.transport.write(0x09);
+ return true;
case KeyEvent.KEYCODE_CAMERA:
// check to see which shortcut the camera button triggers
@@ -362,10 +424,10 @@ public class TerminalKeyListener implements OnKeyListener, OnSharedPreferenceCha
}
} else {
if ((metaState & META_CTRL_ON) != 0) {
- ((vt320)buffer).keyTyped(vt320.KEY_ESCAPE, ' ', 0);
+ sendEscape();
metaState &= ~META_CTRL_ON;
} else
- metaState |= META_CTRL_ON;
+ metaPress(META_CTRL_ON);
}
bridge.redraw();
@@ -389,6 +451,25 @@ public class TerminalKeyListener implements OnKeyListener, OnSharedPreferenceCha
return false;
}
+ public int keyAsControl(int key) {
+ // Support CTRL-a through CTRL-z
+ if (key >= 0x61 && key <= 0x7A)
+ key -= 0x60;
+ // Support CTRL-A through CTRL-_
+ else if (key >= 0x41 && key <= 0x5F)
+ key -= 0x40;
+ // CTRL-space sends NULL
+ else if (key == 0x20)
+ key = 0x00;
+ // CTRL-? sends DEL
+ else if (key == 0x3F)
+ key = 0x7F;
+ return key;
+ }
+
+ public void sendEscape() {
+ ((vt320)buffer).keyTyped(vt320.KEY_ESCAPE, ' ', 0);
+ }
/**
* @param key
@@ -440,7 +521,7 @@ public class TerminalKeyListener implements OnKeyListener, OnSharedPreferenceCha
*
* @param code
*/
- private void metaPress(int code) {
+ public void metaPress(int code) {
if ((metaState & (code << 1)) != 0) {
metaState &= ~(code << 1);
} else if ((metaState & code) != 0) {
@@ -472,6 +553,10 @@ public class TerminalKeyListener implements OnKeyListener, OnSharedPreferenceCha
return metaState;
}
+ public int getDeadKey() {
+ return mDeadKey;
+ }
+
public void setClipboardManager(ClipboardManager clipboard) {
this.clipboard = clipboard;
}
diff --git a/src/org/connectbot/service/TerminalManager.java b/src/org/connectbot/service/TerminalManager.java
index c378b14..86a30f5 100644
--- a/src/org/connectbot/service/TerminalManager.java
+++ b/src/org/connectbot/service/TerminalManager.java
@@ -135,6 +135,7 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen
pubkeydb = new PubkeyDatabase(this);
// load all marked pubkeys into memory
+ updateSavingKeys();
List<PubkeyBean> pubkeys = pubkeydb.getAllStartPubkeys();
for (PubkeyBean pubkey : pubkeys) {
@@ -162,7 +163,6 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen
connectivityManager = new ConnectivityReceiver(this, lockingWifi);
- updateSavingKeys();
}
private void updateSavingKeys() {
@@ -246,6 +246,10 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen
connectivityManager.incRef();
}
+ if (prefs.getBoolean(PreferenceConstants.CONNECTION_PERSIST, true)) {
+ ConnectionNotifier.getInstance().showRunningNotification(this);
+ }
+
// also update database with new connected time
touchHost(host);
@@ -323,6 +327,8 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen
* Called by child bridge when somehow it's been disconnected.
*/
public void onDisconnected(TerminalBridge bridge) {
+ boolean shouldHideRunningNotification = false;
+
synchronized (bridges) {
// remove this bridge from our list
bridges.remove(bridge);
@@ -333,16 +339,24 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen
if (bridge.isUsingNetwork()) {
connectivityManager.decRef();
}
+
+ if (bridges.size() == 0 &&
+ mPendingReconnect.size() == 0) {
+ shouldHideRunningNotification = true;
+ }
}
synchronized (disconnected) {
disconnected.add(bridge.host);
}
+ if (shouldHideRunningNotification) {
+ ConnectionNotifier.getInstance().hideRunningNotification(this);
+ }
+
// pass notification back up to gui
if (disconnectHandler != null)
Message.obtain(disconnectHandler, -1, bridge).sendToTarget();
-
}
public boolean isKeyLoaded(String nickname) {
@@ -350,7 +364,11 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen
}
public void addKey(PubkeyBean pubkey, Object trileadKey) {
- if (!savingKeys)
+ addKey(pubkey, trileadKey, false);
+ }
+
+ public void addKey(PubkeyBean pubkey, Object trileadKey, boolean force) {
+ if (!savingKeys && !force)
return;
removeKey(pubkey.getNickname());
@@ -465,8 +483,6 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen
setResizeAllowed(true);
- ConnectionNotifier.getInstance().hideRunningNotification(this);
-
stopIdleTimer();
// Make sure we stay running to maintain the bridges
@@ -476,13 +492,20 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen
}
@Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ /*
+ * We want this service to continue running until it is explicitly
+ * stopped, so return sticky.
+ */
+ return START_STICKY;
+ }
+
+ @Override
public void onRebind(Intent intent) {
super.onRebind(intent);
setResizeAllowed(true);
- ConnectionNotifier.getInstance().hideRunningNotification(this);
-
Log.i(TAG, "Someone rebound to TerminalManager");
stopIdleTimer();
@@ -496,13 +519,6 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen
if (bridges.size() == 0) {
stopWithDelay();
- } else {
- /* If user wants the connections to stay alive at all costs,
- * set the service to be "foreground."
- */
- if (prefs.getBoolean(PreferenceConstants.CONNECTION_PERSIST, true)) {
- ConnectionNotifier.getInstance().showRunningNotification(this);
- }
}
return true;
@@ -565,7 +581,7 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen
vibrate();
}
- class BeepListener implements OnCompletionListener {
+ private static class BeepListener implements OnCompletionListener {
public void onCompletion(MediaPlayer mp) {
mp.seekTo(0);
}
@@ -647,6 +663,7 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen
disconnectAll(false);
}
};
+ t.setName("Disconnector");
t.start();
}
@@ -660,6 +677,7 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen
reconnectPending();
}
};
+ t.setName("Reconnector");
t.start();
}
@@ -673,7 +691,8 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen
public void requestReconnect(TerminalBridge bridge) {
synchronized (mPendingReconnect) {
mPendingReconnect.add(new WeakReference<TerminalBridge>(bridge));
- if (connectivityManager.isConnected()) {
+ if (!bridge.isUsingNetwork() ||
+ connectivityManager.isConnected()) {
reconnectPending();
}
}
diff --git a/src/org/connectbot/util/EastAsianWidth.java b/src/org/connectbot/util/EastAsianWidth.java
index b27cd48..0e274b5 100644
--- a/src/org/connectbot/util/EastAsianWidth.java
+++ b/src/org/connectbot/util/EastAsianWidth.java
@@ -17,42 +17,59 @@
package org.connectbot.util;
-import android.util.Log;
+import android.graphics.Paint;
+import android.text.AndroidCharacter;
/**
* @author Kenny Root
*
*/
-public class EastAsianWidth {
- public static boolean useJNI = false;
- private static final String TAG = "ConnectBot.EastAsianWidth";
+public abstract class EastAsianWidth {
+ public static EastAsianWidth getInstance() {
+ if (PreferenceConstants.PRE_FROYO)
+ return PreFroyo.Holder.sInstance;
+ else
+ return FroyoAndBeyond.Holder.sInstance;
+ }
/**
* @param charArray
* @param i
* @param position
* @param wideAttribute
- * @param isLegacyEastAsian
*/
- public native static void measure(char[] charArray, int start, int end,
- byte[] wideAttribute, boolean isLegacyEastAsian);
-
- static {
- try {
- System.loadLibrary("org_connectbot_util_EastAsianWidth");
-
- char[] testInput = {(char)0x4EBA};
- byte[] testResult = new byte[1];
- measure(testInput, 0, 1, testResult, true);
-
- if (testResult[0] == 1)
- useJNI = true;
- else
- Log.d(TAG, "EastAsianWidth JNI measuring not available");
- } catch (Exception e) {
- // Failure
- } catch (UnsatisfiedLinkError e1) {
- // Failure
+ public abstract void measure(char[] charArray, int start, int end,
+ byte[] wideAttribute, Paint paint, int charWidth);
+
+ private static class PreFroyo extends EastAsianWidth {
+ private static final int BUFFER_SIZE = 4096;
+ private float[] mWidths = new float[BUFFER_SIZE];
+
+ private static class Holder {
+ private static final PreFroyo sInstance = new PreFroyo();
+ }
+
+ @Override
+ public void measure(char[] charArray, int start, int end,
+ byte[] wideAttribute, Paint paint, int charWidth) {
+ paint.getTextWidths(charArray, start, end, mWidths);
+ final int N = end - start;
+ for (int i = 0; i < N; i++)
+ wideAttribute[i] = (byte) (((int)mWidths[i] != charWidth) ?
+ AndroidCharacter.EAST_ASIAN_WIDTH_WIDE :
+ AndroidCharacter.EAST_ASIAN_WIDTH_NARROW);
+ }
+ }
+
+ private static class FroyoAndBeyond extends EastAsianWidth {
+ private static class Holder {
+ private static final FroyoAndBeyond sInstance = new FroyoAndBeyond();
+ }
+
+ @Override
+ public void measure(char[] charArray, int start, int end,
+ byte[] wideAttribute, Paint paint, int charWidth) {
+ AndroidCharacter.getEastAsianWidths(charArray, start, end - start, wideAttribute);
}
}
}
diff --git a/src/org/connectbot/util/HostDatabase.java b/src/org/connectbot/util/HostDatabase.java
index b0dce6d..2a92bab 100644
--- a/src/org/connectbot/util/HostDatabase.java
+++ b/src/org/connectbot/util/HostDatabase.java
@@ -124,6 +124,9 @@ public class HostDatabase extends RobustSQLiteOpenHelper {
"CREATE INDEX " + TABLE_COLOR_DEFAULTS + FIELD_COLOR_SCHEME + "index ON "
+ TABLE_COLOR_DEFAULTS + " (" + FIELD_COLOR_SCHEME + ");";
+ private static final String WHERE_SCHEME_AND_COLOR = FIELD_COLOR_SCHEME + " = ? AND "
+ + FIELD_COLOR_NUMBER + " = ?";
+
static {
addTableName(TABLE_HOSTS);
addTableName(TABLE_PORTFORWARDS);
@@ -273,8 +276,6 @@ public class HostDatabase extends RobustSQLiteOpenHelper {
SQLiteDatabase db = this.getWritableDatabase();
db.update(TABLE_HOSTS, values, "_id = ?", new String[] { String.valueOf(host.getId()) });
-
- db.close();
}
}
@@ -288,8 +289,6 @@ public class HostDatabase extends RobustSQLiteOpenHelper {
SQLiteDatabase db = this.getWritableDatabase();
id = db.insert(TABLE_HOSTS, null, host.getValues());
-
- db.close();
}
host.setId(id);
@@ -314,7 +313,6 @@ public class HostDatabase extends RobustSQLiteOpenHelper {
db.update(TABLE_HOSTS, updates, "_id = ?",
new String[] { String.valueOf(id) });
- db.close();
}
return true;
@@ -330,7 +328,6 @@ public class HostDatabase extends RobustSQLiteOpenHelper {
synchronized (dbLock) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_HOSTS, "_id = ?", new String[] { String.valueOf(host.getId()) });
- db.close();
}
}
@@ -350,7 +347,6 @@ public class HostDatabase extends RobustSQLiteOpenHelper {
hosts = createHostBeans(c);
c.close();
- db.close();
}
return hosts;
@@ -473,8 +469,6 @@ public class HostDatabase extends RobustSQLiteOpenHelper {
null, null, null);
host = getFirstHostBean(c);
-
- db.close();
}
return host;
@@ -495,8 +489,6 @@ public class HostDatabase extends RobustSQLiteOpenHelper {
null, null, null);
host = getFirstHostBean(c);
-
- db.close();
}
return host;
@@ -521,8 +513,6 @@ public class HostDatabase extends RobustSQLiteOpenHelper {
FIELD_HOST_HOSTNAME + " = ? AND " + FIELD_HOST_PORT + " = ?",
new String[] { hostname, String.valueOf(port) });
Log.d(TAG, String.format("Finished saving hostkey information for '%s'", hostname));
-
- db.close();
}
}
@@ -563,8 +553,6 @@ public class HostDatabase extends RobustSQLiteOpenHelper {
c.close();
}
-
- db.close();
}
return known;
@@ -584,7 +572,6 @@ public class HostDatabase extends RobustSQLiteOpenHelper {
SQLiteDatabase db = this.getWritableDatabase();
db.update(TABLE_HOSTS, values, FIELD_HOST_PUBKEYID + " = ?", new String[] { String.valueOf(pubkeyId) });
- db.close();
}
Log.d(TAG, String.format("Set all hosts using pubkey id %d to -1", pubkeyId));
@@ -624,7 +611,6 @@ public class HostDatabase extends RobustSQLiteOpenHelper {
}
c.close();
- db.close();
}
return portForwards;
@@ -649,8 +635,6 @@ public class HostDatabase extends RobustSQLiteOpenHelper {
if (db.update(TABLE_PORTFORWARDS, pfb.getValues(), "_id = ?", new String[] { String.valueOf(pfb.getId()) }) > 0)
success = true;
}
-
- db.close();
}
return success;
@@ -667,7 +651,6 @@ public class HostDatabase extends RobustSQLiteOpenHelper {
synchronized (dbLock) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_PORTFORWARDS, "_id = ?", new String[] { String.valueOf(pfb.getId()) });
- db.close();
}
}
@@ -688,52 +671,38 @@ public class HostDatabase extends RobustSQLiteOpenHelper {
}
c.close();
- db.close();
}
return colors;
}
public void setColorForScheme(int scheme, int number, int value) {
- SQLiteDatabase db;
+ final SQLiteDatabase db;
- String schemeWhere;
- schemeWhere = FIELD_COLOR_SCHEME + " = ?";
+ final String[] whereArgs = new String[] { String.valueOf(scheme), String.valueOf(number) };
if (value == Colors.defaults[number]) {
- String[] whereArgs = new String[1];
-
- whereArgs[0] = String.valueOf(number);
-
synchronized (dbLock) {
db = getWritableDatabase();
db.delete(TABLE_COLORS,
- FIELD_COLOR_NUMBER + " = ? AND "
- + schemeWhere,
- new String[] { String.valueOf(number) });
-
- db.close();
+ WHERE_SCHEME_AND_COLOR, whereArgs);
}
} else {
- ContentValues values = new ContentValues();
- values.put(FIELD_COLOR_NUMBER, number);
+ final ContentValues values = new ContentValues();
values.put(FIELD_COLOR_VALUE, value);
- String[] whereArgs = null;
-
- whereArgs = new String[] { String.valueOf(scheme) };
-
synchronized (dbLock) {
db = getWritableDatabase();
- int rowsAffected = db.update(TABLE_COLORS, values,
- schemeWhere, whereArgs);
+
+ final int rowsAffected = db.update(TABLE_COLORS, values,
+ WHERE_SCHEME_AND_COLOR, whereArgs);
if (rowsAffected == 0) {
+ values.put(FIELD_COLOR_SCHEME, scheme);
+ values.put(FIELD_COLOR_NUMBER, number);
db.insert(TABLE_COLORS, null, values);
}
-
- db.close();
}
}
}
@@ -760,8 +729,6 @@ public class HostDatabase extends RobustSQLiteOpenHelper {
}
c.close();
-
- db.close();
}
return colors;
@@ -794,8 +761,6 @@ public class HostDatabase extends RobustSQLiteOpenHelper {
values.put(FIELD_COLOR_SCHEME, scheme);
db.insert(TABLE_COLOR_DEFAULTS, null, values);
}
-
- db.close();
}
}
}
diff --git a/src/org/connectbot/util/PreferenceConstants.java b/src/org/connectbot/util/PreferenceConstants.java
index 37e1871..9e37017 100644
--- a/src/org/connectbot/util/PreferenceConstants.java
+++ b/src/org/connectbot/util/PreferenceConstants.java
@@ -26,7 +26,7 @@ import android.os.Build;
public class PreferenceConstants {
public static final boolean PRE_ECLAIR = (Integer.parseInt(Build.VERSION.SDK) <= 4);
public static final boolean PRE_FROYO = PRE_ECLAIR ? true :
- (Build.VERSION.SDK_INT <= 7);
+ (Integer.parseInt(Build.VERSION.SDK) <= 7);
public static final String MEMKEYS = "memkeys";
public static final String UPDATE = "update";
diff --git a/src/org/connectbot/util/UberColorPickerDialog.java b/src/org/connectbot/util/UberColorPickerDialog.java
index e12307e..2c01b30 100644
--- a/src/org/connectbot/util/UberColorPickerDialog.java
+++ b/src/org/connectbot/util/UberColorPickerDialog.java
@@ -65,8 +65,8 @@ import android.view.View;
* @author Keith Wiley, kwiley@keithwiley.com, http://keithwiley.com
*/
public class UberColorPickerDialog extends Dialog {
- private OnColorChangedListener mListener;
- private int mInitialColor;
+ private final OnColorChangedListener mListener;
+ private final int mInitialColor;
/**
* Callback to the creator of the dialog, informing the creator of a new color and notifying that the dialog is about to dismiss.