diff options
author | Jeffrey Sharkey <jsharkey@jsharkey.org> | 2008-10-25 02:34:26 +0000 |
---|---|---|
committer | Jeffrey Sharkey <jsharkey@jsharkey.org> | 2008-10-25 02:34:26 +0000 |
commit | 019443eaa1e97d9b41bbd1cc643c18fc5c67a9e0 (patch) | |
tree | ff7ade6c06157ba70aa4d759a78ca119b00c2a75 /src | |
parent | 06af7451f030963445eb46ec87ed76a1a1ddba25 (diff) | |
download | connectbot-019443eaa1e97d9b41bbd1cc643c18fc5c67a9e0.tar.gz connectbot-019443eaa1e97d9b41bbd1cc643c18fc5c67a9e0.tar.bz2 connectbot-019443eaa1e97d9b41bbd1cc643c18fc5c67a9e0.zip |
* added real password prompt to help with special chars and also offer visual confirmation
* this approach should also work with mutiple auth methods, and handles when switching between multiple consoles correctly
* also simplified wizardactivity
Diffstat (limited to 'src')
-rw-r--r-- | src/org/connectbot/ConsoleActivity.java | 171 | ||||
-rw-r--r-- | src/org/connectbot/HostListActivity.java | 117 | ||||
-rw-r--r-- | src/org/connectbot/R.java | 4 | ||||
-rw-r--r-- | src/org/connectbot/TerminalView.java | 2 | ||||
-rw-r--r-- | src/org/connectbot/WizardActivity.java | 107 | ||||
-rw-r--r-- | src/org/connectbot/service/TerminalBridge.java | 55 |
6 files changed, 277 insertions, 179 deletions
diff --git a/src/org/connectbot/ConsoleActivity.java b/src/org/connectbot/ConsoleActivity.java index 9417f65..450322e 100644 --- a/src/org/connectbot/ConsoleActivity.java +++ b/src/org/connectbot/ConsoleActivity.java @@ -30,7 +30,9 @@ import android.content.Intent; import android.content.ServiceConnection; import android.net.Uri; import android.os.Bundle; +import android.os.Handler; import android.os.IBinder; +import android.os.Message; import android.text.ClipboardManager; import android.util.Log; import android.view.GestureDetector; @@ -40,11 +42,14 @@ import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; +import android.view.ViewConfiguration; import android.view.Window; import android.view.MenuItem.OnMenuItemClickListener; +import android.view.View.OnKeyListener; import android.view.View.OnTouchListener; import android.view.animation.Animation; import android.view.animation.AnimationUtils; +import android.widget.EditText; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.ViewFlipper; @@ -88,6 +93,9 @@ public class ConsoleActivity extends Activity { // create views for all bridges on this service for(TerminalBridge bridge : bound.bridges) { + // let them know about our password services + bridge.passwordHandler = passwordHandler; + // inflate each terminal view RelativeLayout view = (RelativeLayout)inflater.inflate(R.layout.item_terminal, flip, false); @@ -112,6 +120,7 @@ public class ConsoleActivity extends Activity { // show the requested bridge if found, also fade out overlay flip.setDisplayedChild(requestedIndex); flip.getCurrentView().findViewById(R.id.terminal_overlay).startAnimation(fade_out); + updatePasswordVisible(); } @@ -122,7 +131,47 @@ public class ConsoleActivity extends Activity { } }; - protected Animation fade_out = null; + protected String getCurrentNickname() { + View view = findCurrentView(R.id.console_flip); + if(!(view instanceof TerminalView)) return null; + return ((TerminalView)view).bridge.nickname; + } + + + public Handler passwordHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + // someone below us requested to display a password dialog + // they are sending nickname and requested + String nickname = (String)msg.obj; + + // if they are currently active, then obey request + if(nickname.equals(getCurrentNickname())) { + updatePasswordVisible(); + } + + } + }; + + protected void updatePasswordVisible() { + // check if our currently-visible terminalbridge is requesting password services + View view = findCurrentView(R.id.console_flip); + boolean requested = false; + if(view instanceof TerminalView) + requested = ((TerminalView)view).bridge.passwordRequested; + + // handle showing/hiding password field and transferring focus + if(requested) { + this.password.setVisibility(View.VISIBLE); + this.password.setText(""); + this.password.setHint(((TerminalView)view).bridge.passwordHint); + this.password.requestFocus(); + } else { + this.password.setVisibility(View.GONE); + view.requestFocus(); + } + + } /** * Save the currently shown {@link TerminalView} as the default. This is @@ -131,13 +180,14 @@ public class ConsoleActivity extends Activity { */ protected void updateDefault() { // update the current default terminal - TerminalView terminal = (TerminalView)flip.getCurrentView().findViewById(R.id.console_flip); - if(bound == null || terminal == null) return; + View view = findCurrentView(R.id.console_flip); + if(!(view instanceof TerminalView)) return; + + TerminalView terminal = (TerminalView)view; + if(bound == null) return; bound.defaultBridge = terminal.bridge; } - protected Uri requested; - @Override public void onStart() { super.onStart(); @@ -149,7 +199,7 @@ public class ConsoleActivity extends Activity { } @Override - public void onStop() { + public void onStop() { super.onStop(); this.unbindService(connection); @@ -161,7 +211,12 @@ public class ConsoleActivity extends Activity { return view.findViewById(id); } + protected Uri requested; protected ClipboardManager clipboard; + + protected EditText password; + + protected Animation slide_left_in, slide_left_out, slide_right_in, slide_right_out, fade_stay_hidden, fade_out; @Override public void onCreate(Bundle icicle) { @@ -176,17 +231,36 @@ public class ConsoleActivity extends Activity { this.requested = this.getIntent().getData(); this.inflater = (LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - this.flip = (ViewFlipper)this.findViewById(R.id.console_flip); - this.fade_out = AnimationUtils.loadAnimation(this, R.anim.fade_out); + this.flip = (ViewFlipper)this.findViewById(R.id.console_flip); + this.password = (EditText)this.findViewById(R.id.console_password); + this.password.setOnKeyListener(new OnKeyListener() { + public boolean onKey(View v, int keyCode, KeyEvent event) { + if(keyCode != KeyEvent.KEYCODE_ENTER) return false; + + // pass collected password down to current terminal + String value = password.getText().toString(); + + View view = findCurrentView(R.id.console_flip); + if(!(view instanceof TerminalView)) return true; + ((TerminalView)view).bridge.incomingPassword(value); + + // finally clear password for next user + password.setText(""); + return true; + } + }); + // preload animations for terminal switching - final Animation slide_left_in = AnimationUtils.loadAnimation(this, R.anim.slide_left_in); - final Animation slide_left_out = AnimationUtils.loadAnimation(this, R.anim.slide_left_out); - final Animation slide_right_in = AnimationUtils.loadAnimation(this, R.anim.slide_right_in); - final Animation slide_right_out = AnimationUtils.loadAnimation(this, R.anim.slide_right_out); - final Animation fade_stay_hidden = AnimationUtils.loadAnimation(this, R.anim.fade_stay_hidden); + this.slide_left_in = AnimationUtils.loadAnimation(this, R.anim.slide_left_in); + this.slide_left_out = AnimationUtils.loadAnimation(this, R.anim.slide_left_out); + this.slide_right_in = AnimationUtils.loadAnimation(this, R.anim.slide_right_in); + this.slide_right_out = AnimationUtils.loadAnimation(this, R.anim.slide_right_out); + + this.fade_out = AnimationUtils.loadAnimation(this, R.anim.fade_out); + this.fade_stay_hidden = AnimationUtils.loadAnimation(this, R.anim.fade_stay_hidden); // detect fling gestures to switch between terminals final GestureDetector detect = new GestureDetector(new GestureDetector.SimpleOnGestureListener() { @@ -202,7 +276,7 @@ public class ConsoleActivity extends Activity { } // activate consider if within x tolerance - if(Math.abs(e1.getX() - e2.getX()) < 100) { + if(Math.abs(e1.getX() - e2.getX()) < ViewConfiguration.getTouchSlop() * 4) { View flip = findCurrentView(R.id.console_flip); if(flip == null) return false; @@ -224,12 +298,10 @@ public class ConsoleActivity extends Activity { } else { // otherwise consume as pgup/pgdown for every 5 lines if(moved > 5) { - Log.d(this.getClass().toString(), "going pagedown"); ((vt320)terminal.bridge.buffer).keyPressed(vt320.KEY_PAGE_DOWN, ' ', 0); totalY = 0; return true; } else if(moved < -5) { - Log.d(this.getClass().toString(), "going pageup"); ((vt320)terminal.bridge.buffer).keyPressed(vt320.KEY_PAGE_UP, ' ', 0); totalY = 0; return true; @@ -237,7 +309,6 @@ public class ConsoleActivity extends Activity { } - } return false; @@ -256,36 +327,12 @@ public class ConsoleActivity extends Activity { // make sure user kept a steady hand horizontally if(Math.abs(disty) < 100) { if(distx > goalwidth) { - - // keep current overlay from popping up again - View overlay = findCurrentView(R.id.terminal_overlay); - if(overlay != null) overlay.startAnimation(fade_stay_hidden); - - flip.setInAnimation(slide_right_in); - flip.setOutAnimation(slide_right_out); - flip.showPrevious(); - ConsoleActivity.this.updateDefault(); - - // show overlay on new slide and start fade - overlay = findCurrentView(R.id.terminal_overlay); - if(overlay != null) overlay.startAnimation(fade_out); + shiftRight(); return true; } if(distx < -goalwidth) { - - // keep current overlay from popping up again - View overlay = findCurrentView(R.id.terminal_overlay); - if(overlay != null) overlay.startAnimation(fade_stay_hidden); - - flip.setInAnimation(slide_left_in); - flip.setOutAnimation(slide_left_out); - flip.showNext(); - ConsoleActivity.this.updateDefault(); - - // show overlay on new slide and start fade - overlay = findCurrentView(R.id.terminal_overlay); - if(overlay != null) overlay.startAnimation(fade_out); + shiftLeft(); return true; } @@ -299,7 +346,6 @@ public class ConsoleActivity extends Activity { }); - flip.setLongClickable(true); flip.setOnTouchListener(new OnTouchListener() { @@ -310,9 +356,43 @@ public class ConsoleActivity extends Activity { }); + } + + protected void shiftLeft() { + // keep current overlay from popping up again + View overlay = findCurrentView(R.id.terminal_overlay); + if(overlay != null) overlay.startAnimation(fade_stay_hidden); + + flip.setInAnimation(slide_left_in); + flip.setOutAnimation(slide_left_out); + flip.showNext(); + ConsoleActivity.this.updateDefault(); + + // show overlay on new slide and start fade + overlay = findCurrentView(R.id.terminal_overlay); + if(overlay != null) overlay.startAnimation(fade_out); + + updatePasswordVisible(); + + } + protected void shiftRight() { + // keep current overlay from popping up again + View overlay = findCurrentView(R.id.terminal_overlay); + if(overlay != null) overlay.startAnimation(fade_stay_hidden); + flip.setInAnimation(slide_right_in); + flip.setOutAnimation(slide_right_out); + flip.showPrevious(); + ConsoleActivity.this.updateDefault(); + + // show overlay on new slide and start fade + overlay = findCurrentView(R.id.terminal_overlay); + if(overlay != null) overlay.startAnimation(fade_out); + + updatePasswordVisible(); + } protected MenuItem copy, paste; @@ -331,6 +411,7 @@ public class ConsoleActivity extends Activity { TerminalView terminal = (TerminalView)view; bound.disconnect(terminal.bridge); flip.removeView(flip.getCurrentView()); + shiftLeft(); return true; } }); @@ -338,7 +419,7 @@ public class ConsoleActivity extends Activity { copy = menu.add("Copy"); copy.setIcon(android.R.drawable.ic_menu_set_as); copy.setEnabled(false); - // TODO: implement copy here :) + // TODO: freeze current console, allow selection, and set clipboard to contents paste = menu.add("Paste"); diff --git a/src/org/connectbot/HostListActivity.java b/src/org/connectbot/HostListActivity.java index 30ec5f9..9512d07 100644 --- a/src/org/connectbot/HostListActivity.java +++ b/src/org/connectbot/HostListActivity.java @@ -67,7 +67,7 @@ public class HostListActivity extends ListActivity { } }; - public TerminalManager bound = null; + protected TerminalManager bound = null; private ServiceConnection connection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { @@ -83,11 +83,10 @@ public class HostListActivity extends ListActivity { } }; - public HostDatabase hostdb; - public Cursor hosts; - public ListView list; + protected HostDatabase hostdb; + protected Cursor hosts; - public int COL_ID, COL_NICKNAME, COL_USERNAME, COL_HOSTNAME, COL_CONNECTED, COL_PORT; + protected int COL_ID, COL_NICKNAME, COL_USERNAME, COL_HOSTNAME, COL_CONNECTED, COL_PORT; @Override public void onStart() { @@ -109,23 +108,34 @@ public class HostListActivity extends ListActivity { public final static String EULA = "eula"; + + public final static int REQUEST_EDIT = 1; + public final static int REQUEST_EULA = 2; + protected SharedPreferences prefs = null; @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if(resultCode == Activity.RESULT_OK) { - // yay they agreed, so store that info - Editor edit = prefs.edit(); - edit.putBoolean(EULA, true); - edit.commit(); - } else { - // user didnt agree, so close - this.finish(); + switch(requestCode) { + case REQUEST_EULA: + if(resultCode == Activity.RESULT_OK) { + // yay they agreed, so store that info + Editor edit = prefs.edit(); + edit.putBoolean(EULA, true); + edit.commit(); + } else { + // user didnt agree, so close + this.finish(); + } + break; + + case REQUEST_EDIT: + this.updateCursor(); + break; + } - this.updateCursor(); - } @@ -142,7 +152,7 @@ public class HostListActivity extends ListActivity { boolean agreed = prefs.getBoolean(EULA, false); if(!agreed) { - this.startActivityForResult(new Intent(this, WizardActivity.class), 1); + this.startActivityForResult(new Intent(this, WizardActivity.class), REQUEST_EULA); } // start thread to check for new version @@ -155,7 +165,7 @@ public class HostListActivity extends ListActivity { // connect with hosts database and populate list this.hostdb = new HostDatabase(this); - this.list = this.getListView(); + ListView list = this.getListView(); this.updateCursor(); //this.list.setSelector(R.drawable.highlight_disabled_pressed); @@ -167,7 +177,7 @@ public class HostListActivity extends ListActivity { this.COL_PORT = hosts.getColumnIndexOrThrow(HostDatabase.FIELD_HOST_PORT); this.COL_CONNECTED = hosts.getColumnIndexOrThrow(HostDatabase.FIELD_HOST_LASTCONNECT); - this.list.setOnItemClickListener(new OnItemClickListener() { + list.setOnItemClickListener(new OnItemClickListener() { public synchronized void onItemClick(AdapterView<?> parent, View view, int position, long id) { @@ -208,7 +218,7 @@ public class HostListActivity extends ListActivity { }); - this.registerForContextMenu(this.list); + this.registerForContextMenu(list); final Pattern hostmask = Pattern.compile(".+@.+(:\\d+)?"); final TextView text = (TextView) this.findViewById(R.id.front_quickconnect); @@ -216,40 +226,38 @@ public class HostListActivity extends ListActivity { public boolean onKey(View v, int keyCode, KeyEvent event) { - if(keyCode == KeyEvent.KEYCODE_ENTER) { - - // make sure we follow pattern - if (text.getText().length() < 3) - return false; - - // show error if poorly formed - if (!hostmask.matcher(text.getText().toString()).find()) { - text.setError("Use the format 'username@hostname:port'"); - return false; - } - - // create new host for entered string and then launch - Uri uri = Uri.parse(String.format("ssh://%s", text.getText().toString())); - String username = uri.getUserInfo(); - String hostname = uri.getHost(); - int port = uri.getPort(); - if(port == -1) port = 22; + if(keyCode != KeyEvent.KEYCODE_ENTER) return false; - String nickname = String.format("%s@%s", username, hostname); - hostdb.createHost(null, nickname, username, hostname, port, hostdb.COLOR_GRAY); - - Intent intent = new Intent(HostListActivity.this, ConsoleActivity.class); - intent.setData(Uri.parse(String.format("ssh://%s@%s:%s/#%s", username, hostname, port, nickname))); - HostListActivity.this.startActivity(intent); - + // make sure we follow pattern + if (text.getText().length() < 3) + return false; + + // show error if poorly formed + if (!hostmask.matcher(text.getText().toString()).find()) { + text.setError("Use the format 'username@hostname:port'"); + return false; } + + // create new host for entered string and then launch + Uri uri = Uri.parse(String.format("ssh://%s", text.getText().toString())); + String username = uri.getUserInfo(); + String hostname = uri.getHost(); + int port = uri.getPort(); + if(port == -1) port = 22; + + String nickname = String.format("%s@%s", username, hostname); + hostdb.createHost(null, nickname, username, hostname, port, hostdb.COLOR_GRAY); + + Intent intent = new Intent(HostListActivity.this, ConsoleActivity.class); + intent.setData(Uri.parse(String.format("ssh://%s@%s:%s/#%s", username, hostname, port, nickname))); + HostListActivity.this.startActivity(intent); // set list filter based on text // String filter = text.getText().toString(); // list.setTextFilterEnabled((filter.length() > 0)); // list.setFilterText(filter); - return false; + return true; } }); @@ -259,7 +267,7 @@ public class HostListActivity extends ListActivity { public MenuItem sortcolor, sortlast; public boolean sortedByColor = false; - public void updateCursor() { + protected void updateCursor() { // refresh cursor because of possible sorting change if(this.hosts != null) @@ -267,12 +275,12 @@ public class HostListActivity extends ListActivity { this.hosts = this.hostdb.allHosts(sortedByColor); SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.item_host, this.hosts, - new String[] { hostdb.FIELD_HOST_NICKNAME, hostdb.FIELD_HOST_LASTCONNECT, hostdb.FIELD_HOST_LASTCONNECT, hostdb.FIELD_HOST_COLOR }, + new String[] { HostDatabase.FIELD_HOST_NICKNAME, HostDatabase.FIELD_HOST_LASTCONNECT, HostDatabase.FIELD_HOST_LASTCONNECT, HostDatabase.FIELD_HOST_COLOR }, new int[] { android.R.id.text1, android.R.id.text2, android.R.id.icon, android.R.id.content }); adapter.setViewBinder(new HostBinder(bound, this.getResources())); //this.adapter = new HostAdapter(this, this.hosts); - this.list.setAdapter(adapter); + this.setListAdapter(adapter); } @@ -293,14 +301,6 @@ public class HostListActivity extends ListActivity { // add host, ssh keys, about -// MenuItem add = menu.add(0, 0, Menu.NONE, "New host"); -// add.setIcon(android.R.drawable.ic_menu_add); -// add.setOnMenuItemClickListener(new OnMenuItemClickListener() { -// public boolean onMenuItemClick(MenuItem item) { -// return true; -// } -// }); - sortcolor = menu.add("Sort by color"); sortcolor.setIcon(android.R.drawable.ic_menu_share); sortcolor.setOnMenuItemClickListener(new OnMenuItemClickListener() { @@ -337,9 +337,6 @@ public class HostListActivity extends ListActivity { } - - - public final static int REQUEST_EDIT = 1; @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { @@ -348,7 +345,7 @@ public class HostListActivity extends ListActivity { // create menu to handle deleting and sharing lists AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; - Cursor cursor = (Cursor) this.list.getItemAtPosition(info.position); + Cursor cursor = (Cursor) this.getListView().getItemAtPosition(info.position); menu.setHeaderTitle(cursor.getString(COL_NICKNAME)); final int id = cursor.getInt(COL_ID); diff --git a/src/org/connectbot/R.java b/src/org/connectbot/R.java index 416addd..e82a6e1 100644 --- a/src/org/connectbot/R.java +++ b/src/org/connectbot/R.java @@ -41,10 +41,10 @@ public final class R { public static final int action_next=0x7f090005; public static final int action_prev=0x7f090004; public static final int console_flip=0x7f090000; - public static final int front_quickconnect=0x7f090001; + public static final int console_password=0x7f090001; + public static final int front_quickconnect=0x7f090002; public static final int terminal_overlay=0x7f090006; public static final int wizard_flipper=0x7f090003; - public static final int wizard_scroll=0x7f090002; } public static final class layout { public static final int act_console=0x7f030000; diff --git a/src/org/connectbot/TerminalView.java b/src/org/connectbot/TerminalView.java index 8e4c893..d94b84b 100644 --- a/src/org/connectbot/TerminalView.java +++ b/src/org/connectbot/TerminalView.java @@ -24,6 +24,7 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PixelXorXfermode; +import android.os.Handler; import android.view.View; import android.view.ViewGroup.LayoutParams; @@ -59,6 +60,7 @@ public class TerminalView extends View { // connect our view up to the bridge this.setOnKeyListener(bridge); + } public void destroy() { diff --git a/src/org/connectbot/WizardActivity.java b/src/org/connectbot/WizardActivity.java index 1d4c10f..48cba6b 100644 --- a/src/org/connectbot/WizardActivity.java +++ b/src/org/connectbot/WizardActivity.java @@ -34,51 +34,19 @@ import android.widget.ImageView; import android.widget.ScrollView; import android.widget.ViewFlipper; +/** + * Show a series of wizard-like steps to the user, which might include an EULA, + * program credits, and helpful hints. + * + * @author jsharkey + */ public class WizardActivity extends Activity { - - public final static int ACTION_NEXT = +1, ACTION_PREV = -1; - - protected Handler actionHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - - switch(msg.what) { - case ACTION_NEXT: - if(flipper.getDisplayedChild() == flipper.getChildCount() - 1) { - WizardActivity.this.setResult(Activity.RESULT_OK); - WizardActivity.this.finish(); - } else { - flipper.showNext(); - } - break; - case ACTION_PREV: - if(flipper.getDisplayedChild() == 0) { - WizardActivity.this.setResult(Activity.RESULT_CANCELED); - WizardActivity.this.finish(); - } else { - flipper.showPrevious(); - } - break; - - } - - // scroll to top and hide all views except current - scroll.scrollTo(0, 0); - - setButtons(); - - } - }; - - protected void setButtons() { - boolean eula = (flipper.getDisplayedChild() == 0); - - next.setText(eula ? "Agree" : "Next"); - prev.setText(eula ? "Cancel" : "Back"); - - } - - protected ScrollView scroll = null; + + /** + * In-order list of wizard steps to present to user. These are layout resource ids. + */ + public final static int[] STEPS = new int[] { R.layout.wiz_eula, R.layout.wiz_features }; + protected ViewFlipper flipper = null; protected Button next, prev; @@ -87,33 +55,62 @@ public class WizardActivity extends Activity { super.onCreate(savedInstanceState); setContentView(R.layout.act_wizard); - // let the user step through various parts of wizard - // inflate all views to walk through - - LayoutInflater inflater = (LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - - this.scroll = (ScrollView)this.findViewById(R.id.wizard_scroll); this.flipper = (ViewFlipper)this.findViewById(R.id.wizard_flipper); - this.flipper.addView(inflater.inflate(R.layout.wiz_eula, this.flipper, false)); - this.flipper.addView(inflater.inflate(R.layout.wiz_features, this.flipper, false)); + // inflate the layouts for each step + LayoutInflater inflater = (LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + for(int layout : STEPS) { + View step = inflater.inflate(layout, this.flipper, false); + this.flipper.addView(step); + } next = (Button)this.findViewById(R.id.action_next); next.setOnClickListener(new OnClickListener() { public void onClick(View v) { - actionHandler.sendEmptyMessage(ACTION_NEXT); + if(isLastDisplayed()) { + // user walked past end of wizard, so return okay + WizardActivity.this.setResult(Activity.RESULT_OK); + WizardActivity.this.finish(); + } else { + // show next step and update buttons + flipper.showNext(); + updateButtons(); + } } }); prev = (Button)this.findViewById(R.id.action_prev); prev.setOnClickListener(new OnClickListener() { public void onClick(View v) { - actionHandler.sendEmptyMessage(ACTION_PREV); + if(isFirstDisplayed()) { + // user walked past beginning of wizard, so return that they cancelled + WizardActivity.this.setResult(Activity.RESULT_CANCELED); + WizardActivity.this.finish(); + } else { + // show previous step and update buttons + flipper.showPrevious(); + updateButtons(); + } } }); - this.setButtons(); + this.updateButtons(); + + } + + protected boolean isFirstDisplayed() { + return (flipper.getDisplayedChild() == 0); + } + + protected boolean isLastDisplayed() { + return (flipper.getDisplayedChild() == flipper.getChildCount() - 1); + } + + protected void updateButtons() { + boolean eula = (flipper.getDisplayedChild() == 0); + next.setText(eula ? "Agree" : "Next"); + prev.setText(eula ? "Cancel" : "Back"); } diff --git a/src/org/connectbot/service/TerminalBridge.java b/src/org/connectbot/service/TerminalBridge.java index 2a6f276..2cddb52 100644 --- a/src/org/connectbot/service/TerminalBridge.java +++ b/src/org/connectbot/service/TerminalBridge.java @@ -30,6 +30,8 @@ import android.graphics.PixelXorXfermode; import android.graphics.Typeface; import android.graphics.Bitmap.Config; import android.graphics.Paint.FontMetricsInt; +import android.os.Handler; +import android.os.Message; import android.util.Log; import android.view.KeyCharacterMap; import android.view.KeyEvent; @@ -192,7 +194,11 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener { outputLine("Trying to authenticate"); if(connection.isAuthMethodAvailable(username, AUTH_PASSWORD)) { // show auth prompt in window - promptPassword(); + requestPasswordVisible(true, "Password"); + //promptPassword(); + } else { + outputLine("Looks like your host doesn't support 'password' authentication."); + outputLine("Other auth methods, such as interactive and publickey, are still being written."); } } catch (IOException e) { Log.e(TAG, "Problem in SSH connection thread", e); @@ -212,19 +218,33 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener { this.redraw(); } - protected void promptPassword() { - this.outputLine("Password: "); +// protected void promptPassword() { +// this.outputLine("Password: "); +// } + + public boolean passwordRequested = false; + public Handler passwordHandler = null; + public String passwordHint = null; + + protected void requestPasswordVisible(boolean visible, String hint) { + this.passwordRequested = visible; + this.passwordHint = hint; + + // pass notification up to any attached gui + if(this.passwordHandler != null) + Message.obtain(this.passwordHandler, -1, this.nickname).sendToTarget(); } /** * Attempt to try password authentication using given string. */ - public void tryPassword(String password) { + public void incomingPassword(String password) { try { // try authenticating with given password Log.d(TAG, "Attempting to try password authentication"); if(this.connection.authenticateWithPassword(this.username, password)) { this.buffer.deleteArea(0, 0, this.buffer.getColumns(), this.buffer.getRows()); + requestPasswordVisible(false, null); finishConnection(); return; } @@ -232,7 +252,7 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener { Log.e(TAG, "Problem while trying to authenticate with password", e); } this.outputLine("Permission denied, please try again."); - this.promptPassword(); +// this.promptPassword(); } /** @@ -246,6 +266,7 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener { // previously tried vt100 and xterm for emulation modes // "screen" works the best for color and escape codes + // TODO: pull this value from the preferences this.session.requestPTY("screen", 0, 0, 0, 0, null); this.session.startShell(); @@ -305,7 +326,7 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener { * Buffer of collected characters, for example when prompted for password or * accepting a hostkey. */ - protected StringBuffer collected = new StringBuffer(); + //protected StringBuffer collected = new StringBuffer(); /** * Handle onKey() events coming down from a {@link TerminalView} above us. @@ -333,17 +354,17 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener { if(this.session == null) { // check to see if we are collecting password information - if(keyCode == KeyEvent.KEYCODE_ENTER) { - this.tryPassword(collected.toString()); - collected = new StringBuffer(); - return true; - } else if(printing) { - collected.appendCodePoint(keymap.get(keyCode, event.getMetaState())); - return true; - } else if(keyCode == KeyEvent.KEYCODE_DEL && collected.length() > 0) { - collected.deleteCharAt(collected.length() - 1); - return true; - } +// if(keyCode == KeyEvent.KEYCODE_ENTER) { +// this.incomingPassword(collected.toString()); +// collected = new StringBuffer(); +// return true; +// } else if(printing) { +// collected.appendCodePoint(keymap.get(keyCode, event.getMetaState())); +// return true; +// } else if(keyCode == KeyEvent.KEYCODE_DEL && collected.length() > 0) { +// collected.deleteCharAt(collected.length() - 1); +// return true; +// } } else { |