diff options
| -rw-r--r-- | app/src/main/java/org/connectbot/ConsoleActivity.java | 424 | ||||
| -rw-r--r-- | app/src/main/java/org/connectbot/service/TerminalManager.java | 5 | ||||
| -rw-r--r-- | app/src/main/res/layout/act_console.xml | 10 | 
3 files changed, 197 insertions, 242 deletions
| diff --git a/app/src/main/java/org/connectbot/ConsoleActivity.java b/app/src/main/java/org/connectbot/ConsoleActivity.java index 50c1a21..e011c93 100644 --- a/app/src/main/java/org/connectbot/ConsoleActivity.java +++ b/app/src/main/java/org/connectbot/ConsoleActivity.java @@ -20,6 +20,7 @@ package org.connectbot;  import java.lang.ref.WeakReference;  import java.util.List; +import org.connectbot.bean.HostBean;  import org.connectbot.bean.SelectionArea;  import org.connectbot.service.PromptHelper;  import org.connectbot.service.TerminalBridge; @@ -46,7 +47,10 @@ import android.os.Handler;  import android.os.IBinder;  import android.os.Message;  import android.preference.PreferenceManager; +import android.support.v4.app.ActivityCompat;  import android.support.v4.view.MotionEventCompat; +import android.support.v4.view.PagerAdapter; +import android.support.v4.view.ViewPager;  import android.text.ClipboardManager;  import android.util.Log;  import android.view.ContextMenu; @@ -63,6 +67,7 @@ import android.view.View.OnClickListener;  import android.view.View.OnKeyListener;  import android.view.View.OnTouchListener;  import android.view.ViewConfiguration; +import android.view.ViewGroup;  import android.view.Window;  import android.view.WindowManager;  import android.view.animation.Animation; @@ -78,7 +83,6 @@ import android.widget.ListView;  import android.widget.RelativeLayout;  import android.widget.TextView;  import android.widget.Toast; -import android.widget.ViewFlipper;  import de.mud.terminal.vt320;  public class ConsoleActivity extends Activity { @@ -90,12 +94,9 @@ public class ConsoleActivity extends Activity {  	private static final float MAX_CLICK_DISTANCE = 25f;  	private static final int KEYBOARD_DISPLAY_TIME = 1500; -	// Direction to shift the ViewFlipper -	private static final int SHIFT_LEFT = 0; -	private static final int SHIFT_RIGHT = 1; - -	protected ViewFlipper flip = null; +	protected ViewPager pager = null;  	protected TerminalManager bound = null; +	protected TerminalPagerAdapter adapter = null;  	protected LayoutInflater inflater = null;  	private SharedPreferences prefs = null; @@ -120,7 +121,7 @@ public class ConsoleActivity extends Activity {  	private TextView empty; -	private Animation slide_left_in, slide_left_out, slide_right_in, slide_right_out, fade_stay_hidden, fade_out_delayed; +	private Animation fade_out_delayed;  	private Animation keyboard_fade_in, keyboard_fade_out;  	private float lastX, lastY; @@ -150,9 +151,6 @@ public class ConsoleActivity extends Activity {  			bound.disconnectHandler = disconnectHandler;  			bound.setResizeAllowed(true); -			// clear out any existing bridges and record requested index -			flip.removeAllViews(); -  			final String requestedNickname = (requested != null) ? requested.getFragment() : null;  			int requestedIndex = 0; @@ -169,20 +167,14 @@ public class ConsoleActivity extends Activity {  			}  			// create views for all bridges on this service -			for (TerminalBridge bridge : bound.getBridges()) { - -				final int currentIndex = addNewTerminalView(bridge); +			adapter.notifyDataSetChanged(); +			requestedIndex = bound.getBridges().indexOf(requestedBridge); -				// check to see if this bridge was requested -				if (bridge == requestedBridge) -					requestedIndex = currentIndex; -			} - -			setDisplayedTerminal(requestedIndex); +			setDisplayedTerminal(requestedIndex == -1 ? 0 : requestedIndex);  		}  		public void onServiceDisconnected(ComponentName className) { -			flip.removeAllViews(); +			adapter.notifyDataSetChanged();  			updateEmptyVisible();  			bound = null;  		} @@ -205,8 +197,10 @@ public class ConsoleActivity extends Activity {  			// they are sending nickname and requested  			TerminalBridge bridge = (TerminalBridge) msg.obj; -			if (bridge.isAwaitingClose()) +			adapter.notifyDataSetChanged(); +			if (bridge.isAwaitingClose()) {  				closeBridge(bridge); +			}  		}  	}; @@ -214,44 +208,29 @@ public class ConsoleActivity extends Activity {  	 * @param bridge  	 */  	private void closeBridge(final TerminalBridge bridge) { -		synchronized (flip) { -			final int flipIndex = getFlipIndex(bridge); - -			if (flipIndex >= 0) { -				if (flip.getDisplayedChild() == flipIndex) { -					shiftCurrentTerminal(SHIFT_LEFT); -				} -				flip.removeViewAt(flipIndex); - -				/* TODO Remove this workaround when ViewFlipper is fixed to listen -				 * to view removals. Android Issue 1784 -				 */ -				final int numChildren = flip.getChildCount(); -				if (flip.getDisplayedChild() >= numChildren && -						numChildren > 0) { -					flip.setDisplayedChild(numChildren - 1); -				} - -				updateEmptyVisible(); -			} +		synchronized (pager) { +			updateEmptyVisible(); +			updatePromptVisible();  			// If we just closed the last bridge, go back to the previous activity. -			if (flip.getChildCount() == 0) { +			if (pager.getChildCount() == 0) {  				finish();  			}  		}  	}  	protected View findCurrentView(int id) { -		View view = flip.getCurrentView(); -		if (view == null) return null; +		TerminalView view = adapter.getCurrentTerminalView(); +		if (view == null) { +			return null; +		}  		return view.findViewById(id);  	}  	protected PromptHelper getCurrentPromptHelper() { -		View view = findCurrentView(R.id.console_flip); -		if (!(view instanceof TerminalView)) return null; -		return ((TerminalView) view).bridge.promptHelper; +		TerminalView view = adapter.getCurrentTerminalView(); +		if (view == null) return null; +		return view.bridge.promptHelper;  	}  	protected void hideAllPrompts() { @@ -326,8 +305,16 @@ public class ConsoleActivity extends Activity {  		inflater = LayoutInflater.from(this); -		flip = (ViewFlipper) findViewById(R.id.console_flip); -		registerForContextMenu(flip); +		pager = (ViewPager) findViewById(R.id.console_flip); +		registerForContextMenu(pager); +		pager.addOnPageChangeListener( +				new ViewPager.SimpleOnPageChangeListener() { +					@Override +					public void onPageSelected(int position) { +						onTerminalChanged(); +					} +				}); +  		empty = (TextView) findViewById(android.R.id.empty);  		stringPromptGroup = (RelativeLayout) findViewById(R.id.console_password_group); @@ -376,14 +363,7 @@ public class ConsoleActivity extends Activity {  			}  		}); -		// preload animations for terminal switching -		slide_left_in = AnimationUtils.loadAnimation(this, R.anim.slide_left_in); -		slide_left_out = AnimationUtils.loadAnimation(this, R.anim.slide_left_out); -		slide_right_in = AnimationUtils.loadAnimation(this, R.anim.slide_right_in); -		slide_right_out = AnimationUtils.loadAnimation(this, R.anim.slide_right_out); -  		fade_out_delayed = AnimationUtils.loadAnimation(this, R.anim.fade_out_delayed); -		fade_stay_hidden = AnimationUtils.loadAnimation(this, R.anim.fade_stay_hidden);  		// Preload animation for keyboard button  		keyboard_fade_in = AnimationUtils.loadAnimation(this, R.anim.keyboard_fade_in); @@ -396,11 +376,11 @@ public class ConsoleActivity extends Activity {  		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) +				View terminal = adapter.getCurrentTerminalView(); +				if (terminal == null)  					return; -				inputManager.showSoftInput(flip, InputMethodManager.SHOW_FORCED); +				inputManager.showSoftInput(terminal, InputMethodManager.SHOW_FORCED);  				hideEmulatedKeys();  			}  		}); @@ -408,9 +388,8 @@ public class ConsoleActivity extends Activity {  		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; +				TerminalView terminal = adapter.getCurrentTerminalView(); +				if (terminal == null) return;  				TerminalKeyListener handler = terminal.bridge.getKeyHandler();  				handler.metaPress(TerminalKeyListener.OUR_CTRL_ON, true); @@ -421,9 +400,8 @@ public class ConsoleActivity extends Activity {  		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; +				TerminalView terminal = adapter.getCurrentTerminalView(); +				if (terminal == null) return;  				TerminalKeyListener handler = terminal.bridge.getKeyHandler();  				handler.sendEscape(); @@ -434,9 +412,8 @@ public class ConsoleActivity extends Activity {  		final ImageView tabButton = (ImageView) findViewById(R.id.button_tab);  		tabButton.setOnClickListener(new OnClickListener() {  			public void onClick(View view) { -				View flip = findCurrentView(R.id.console_flip); -				if (flip == null) return; -				TerminalView terminal = (TerminalView) flip; +				TerminalView terminal = adapter.getCurrentTerminalView(); +				if (terminal == null) return;  				TerminalKeyListener handler = terminal.bridge.getKeyHandler();  				handler.sendTab(); @@ -463,34 +440,9 @@ public class ConsoleActivity extends Activity {  			private float totalY = 0;  			@Override -			public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { - -				final float distx = e2.getRawX() - e1.getRawX(); -				final float disty = e2.getRawY() - e1.getRawY(); -				final int goalwidth = flip.getWidth() / 2; - -				// need to slide across half of display to trigger console change -				// make sure user kept a steady hand horizontally -				if (Math.abs(disty) < (flip.getHeight() / 4)) { -					if (distx > goalwidth) { -						shiftCurrentTerminal(SHIFT_RIGHT); -						return true; -					} - -					if (distx < -goalwidth) { -						shiftCurrentTerminal(SHIFT_LEFT); -						return true; -					} - -				} - -				return super.onFling(e1, e2, velocityX, velocityY); -			} - -			@Override  			public void onLongPress(MotionEvent e) {  				super.onLongPress(e); -				openContextMenu(flip); +				openContextMenu(pager);  			} @@ -513,9 +465,9 @@ public class ConsoleActivity extends Activity {  				int touchSlop = ViewConfiguration.get(ConsoleActivity.this).getScaledTouchSlop();  				if (Math.abs(e1.getX() - e2.getX()) < touchSlop * 4) { -					View flip = findCurrentView(R.id.console_flip); -					if (flip == null) return false; -					TerminalView terminal = (TerminalView) flip; +					View view = adapter.getCurrentTerminalView(); +					if (view == null) return false; +					TerminalView terminal = (TerminalView) view;  					// estimate how many rows we have scrolled through  					// accumulate distance that doesn't trigger immediate scroll @@ -523,7 +475,7 @@ public class ConsoleActivity extends Activity {  					final int moved = (int) (totalY / terminal.bridge.charHeight);  					// consume as scrollback only if towards right half of screen -					if (e2.getX() > flip.getWidth() / 2) { +					if (e2.getX() > view.getWidth() / 2) {  						if (moved != 0) {  							int base = terminal.bridge.buffer.getWindowBase();  							terminal.bridge.buffer.setWindowBase(base + moved); @@ -554,8 +506,8 @@ public class ConsoleActivity extends Activity {  		}); -		flip.setLongClickable(true); -		flip.setOnTouchListener(new OnTouchListener() { +		pager.setLongClickable(true); +		pager.setOnTouchListener(new OnTouchListener() {  			public boolean onTouch(View v, MotionEvent event) { @@ -564,17 +516,17 @@ public class ConsoleActivity extends Activity {  						MotionEventCompat.getSource(event) == InputDevice.SOURCE_MOUSE &&  						event.getAction() == MotionEvent.ACTION_DOWN) {  					switch (event.getButtonState()) { -						case MotionEvent.BUTTON_PRIMARY: -							// Automatically start copy mode if using a mouse. -							startCopyMode(); -							break; -						case MotionEvent.BUTTON_SECONDARY: -							// Let the context menu show on right click. -							return false; -						case MotionEvent.BUTTON_TERTIARY: -							// Middle click pastes. -							pasteIntoTerminal(); -							return true; +					case MotionEvent.BUTTON_PRIMARY: +						// Automatically start copy mode if using a mouse. +						startCopyMode(); +						break; +					case MotionEvent.BUTTON_SECONDARY: +						openContextMenu(pager); +						return true; +					case MotionEvent.BUTTON_TERTIARY: +						// Middle click pastes. +						pasteIntoTerminal(); +						return true;  					}  				} @@ -638,8 +590,6 @@ public class ConsoleActivity extends Activity {  					}  				} -				Configuration config = getResources().getConfiguration(); -  				if (event.getAction() == MotionEvent.ACTION_DOWN) {  					lastX = event.getX();  					lastY = event.getY(); @@ -652,11 +602,13 @@ public class ConsoleActivity extends Activity {  				}  				// pass any touch events back to detector -				detect.onTouchEvent(event); -				return true; +				return detect.onTouchEvent(event);  			}  		}); + +		adapter = new TerminalPagerAdapter(); +		pager.setAdapter(adapter);  	}  	/** @@ -691,14 +643,14 @@ public class ConsoleActivity extends Activity {  	public boolean onCreateOptionsMenu(Menu menu) {  		super.onCreateOptionsMenu(menu); -		View view = findCurrentView(R.id.console_flip); -		final boolean activeTerminal = (view instanceof TerminalView); +		TerminalView view = adapter.getCurrentTerminalView(); +		final boolean activeTerminal = view != null;  		boolean sessionOpen = false;  		boolean disconnected = false;  		boolean canForwardPorts = false;  		if (activeTerminal) { -			TerminalBridge bridge = ((TerminalView) view).bridge; +			TerminalBridge bridge = view.bridge;  			sessionOpen = bridge.isSessionOpen();  			disconnected = bridge.isDisconnected();  			canForwardPorts = bridge.canFowardPorts(); @@ -716,7 +668,7 @@ public class ConsoleActivity extends Activity {  		disconnect.setOnMenuItemClickListener(new OnMenuItemClickListener() {  			public boolean onMenuItemClick(MenuItem item) {  				// disconnect or close the currently visible session -				TerminalView terminalView = (TerminalView) findCurrentView(R.id.console_flip); +				TerminalView terminalView = adapter.getCurrentTerminalView();  				TerminalBridge bridge = terminalView.bridge;  				bridge.dispatchDisconnect(true); @@ -756,7 +708,7 @@ public class ConsoleActivity extends Activity {  		portForward.setEnabled(sessionOpen && canForwardPorts);  		portForward.setOnMenuItemClickListener(new OnMenuItemClickListener() {  			public boolean onMenuItemClick(MenuItem item) { -				TerminalView terminalView = (TerminalView) findCurrentView(R.id.console_flip); +				TerminalView terminalView = adapter.getCurrentTerminalView();  				TerminalBridge bridge = terminalView.bridge;  				Intent intent = new Intent(ConsoleActivity.this, PortForwardListActivity.class); @@ -773,7 +725,7 @@ public class ConsoleActivity extends Activity {  		urlscan.setEnabled(activeTerminal);  		urlscan.setOnMenuItemClickListener(new OnMenuItemClickListener() {  			public boolean onMenuItemClick(MenuItem item) { -				final TerminalView terminalView = (TerminalView) findCurrentView(R.id.console_flip); +				final TerminalView terminalView = adapter.getCurrentTerminalView();  				List<String> urls = terminalView.bridge.scanForURLs(); @@ -799,7 +751,7 @@ public class ConsoleActivity extends Activity {  		resize.setEnabled(sessionOpen);  		resize.setOnMenuItemClickListener(new OnMenuItemClickListener() {  			public boolean onMenuItemClick(MenuItem item) { -				final TerminalView terminalView = (TerminalView) findCurrentView(R.id.console_flip); +				final TerminalView terminalView = adapter.getCurrentTerminalView();  				final View resizeView = inflater.inflate(R.layout.dia_resize, null, false);  				new AlertDialog.Builder(ConsoleActivity.this) @@ -837,14 +789,14 @@ public class ConsoleActivity extends Activity {  		setVolumeControlStream(AudioManager.STREAM_NOTIFICATION); -		final View view = findCurrentView(R.id.console_flip); -		boolean activeTerminal = (view instanceof TerminalView); +		final TerminalView view = adapter.getCurrentTerminalView(); +		boolean activeTerminal = view != null;  		boolean sessionOpen = false;  		boolean disconnected = false;  		boolean canForwardPorts = false;  		if (activeTerminal) { -			TerminalBridge bridge = ((TerminalView) view).bridge; +			TerminalBridge bridge = view.bridge;  			sessionOpen = bridge.isSessionOpen();  			disconnected = bridge.isDisconnected();  			canForwardPorts = bridge.canFowardPorts(); @@ -886,12 +838,12 @@ public class ConsoleActivity extends Activity {  	@Override  	public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { -		final View view = findCurrentView(R.id.console_flip); -		boolean activeTerminal = (view instanceof TerminalView); +		final TerminalView view = adapter.getCurrentTerminalView(); +		boolean activeTerminal = view != null;  		boolean sessionOpen = false;  		if (activeTerminal) { -			TerminalBridge bridge = ((TerminalView) view).bridge; +			TerminalBridge bridge = view.bridge;  			sessionOpen = bridge.isSessionOpen();  		} @@ -971,7 +923,7 @@ public class ConsoleActivity extends Activity {  		TerminalBridge requestedBridge = bound.getConnectedBridge(requested.getFragment());  		int requestedIndex = 0; -		synchronized (flip) { +		synchronized (pager) {  			if (requestedBridge == null) {  				// If we didn't find the requested connection, try opening it @@ -985,9 +937,10 @@ public class ConsoleActivity extends Activity {  					return;  				} -				requestedIndex = addNewTerminalView(requestedBridge); +				adapter.notifyDataSetChanged(); +				requestedIndex = adapter.getCount();  			} else { -				final int flipIndex = getFlipIndex(requestedBridge); +				final int flipIndex = bound.getBridges().indexOf(requestedBridge);  				if (flipIndex > requestedIndex) {  					requestedIndex = flipIndex;  				} @@ -1006,7 +959,7 @@ public class ConsoleActivity extends Activity {  	private void startCopyMode() {  		// mark as copying and reset any previous bounds -		TerminalView terminalView = (TerminalView) findCurrentView(R.id.console_flip); +		TerminalView terminalView = (TerminalView) adapter.getCurrentTerminalView();  		copySource = terminalView.bridge;  		SelectionArea area = copySource.getSelectionArea(); @@ -1019,42 +972,6 @@ public class ConsoleActivity extends Activity {  		copySource.redraw();  	} -	protected void shiftCurrentTerminal(final int direction) { -		View overlay; -		synchronized (flip) { -			boolean shouldAnimate = flip.getChildCount() > 1; - -			// Only show animation if there is something else to go to. -			if (shouldAnimate) { -				// keep current overlay from popping up again -				overlay = findCurrentView(R.id.terminal_overlay); -				if (overlay != null) -					overlay.startAnimation(fade_stay_hidden); - -				if (direction == SHIFT_LEFT) { -					flip.setInAnimation(slide_left_in); -					flip.setOutAnimation(slide_left_out); -					flip.showNext(); -				} else if (direction == SHIFT_RIGHT) { -					flip.setInAnimation(slide_right_in); -					flip.setOutAnimation(slide_right_out); -					flip.showPrevious(); -				} -			} - -			ConsoleActivity.this.updateDefault(); - -			if (shouldAnimate) { -				// show overlay on new slide and start fade -				overlay = findCurrentView(R.id.terminal_overlay); -				if (overlay != null) -					overlay.startAnimation(fade_out_delayed); -			} - -			updatePromptVisible(); -		} -	} -  	/**  	 * Save the currently shown {@link TerminalView} as the default. This is  	 * saved back down into {@link TerminalManager} where we can read it again @@ -1062,17 +979,16 @@ public class ConsoleActivity extends Activity {  	 */  	private void updateDefault() {  		// update the current default terminal -		View view = findCurrentView(R.id.console_flip); -		if (!(view instanceof TerminalView)) return; +		TerminalView view = adapter.getCurrentTerminalView(); +		if (view == null) return; -		TerminalView terminal = (TerminalView) view;  		if (bound == null) return; -		bound.defaultBridge = terminal.bridge; +		bound.defaultBridge = view.bridge;  	}  	protected void updateEmptyVisible() {  		// update visibility of empty status message -		empty.setVisibility((flip.getChildCount() == 0) ? View.VISIBLE : View.GONE); +		empty.setVisibility((pager.getChildCount() == 0) ? View.VISIBLE : View.GONE);  	}  	/** @@ -1080,17 +996,17 @@ public class ConsoleActivity extends Activity {  	 */  	protected void updatePromptVisible() {  		// check if our currently-visible terminalbridge is requesting any prompt services -		View view = findCurrentView(R.id.console_flip); +		TerminalView view = adapter.getCurrentTerminalView();  		// Hide all the prompts in case a prompt request was canceled  		hideAllPrompts(); -		if (!(view instanceof TerminalView)) { +		if (view == null) {  			// we dont have an active view, so hide any prompts  			return;  		} -		PromptHelper prompt = ((TerminalView) view).bridge.promptHelper; +		PromptHelper prompt = view.bridge.promptHelper;  		if (String.class.equals(prompt.promptRequested)) {  			stringPromptGroup.setVisibility(View.VISIBLE); @@ -1166,9 +1082,31 @@ public class ConsoleActivity extends Activity {  		}  	} +	/** +	 * Called whenever the displayed terminal is changed. +	 */ +	private void onTerminalChanged() { +		View overlay = findCurrentView(R.id.terminal_overlay); +		if (overlay != null) +			overlay.startAnimation(fade_out_delayed); +		updateDefault(); +		updatePromptVisible(); +		ActivityCompat.invalidateOptionsMenu(ConsoleActivity.this); +	} + +	/** +	 * Displays the child in the ViewPager at the requestedIndex and updates the prompts. +	 * +	 * @param requestedIndex the index of the terminal view to display +	 */ +	private void setDisplayedTerminal(int requestedIndex) { +		pager.setCurrentItem(requestedIndex); +		onTerminalChanged(); +	} +  	private void pasteIntoTerminal() {  		// force insert of clipboard text into current console -		TerminalView terminalView = (TerminalView) findCurrentView(R.id.console_flip); +		TerminalView terminalView = adapter.getCurrentTerminalView();  		TerminalBridge bridge = terminalView.bridge;  		// pull string from clipboard and generate all events to force down @@ -1176,75 +1114,91 @@ public class ConsoleActivity extends Activity {  		bridge.injectString(clip);  	} -	/** -	 * Adds a new TerminalBridge to the current set of views in our ViewFlipper. -	 * -	 * @param bridge TerminalBridge to add to our ViewFlipper -	 * @return the child index of the new view in the ViewFlipper -	 */ -	private int addNewTerminalView(TerminalBridge bridge) { -		// let them know about our prompt handler services -		bridge.promptHelper.setHandler(promptHandler); - -		// inflate each terminal view -		RelativeLayout view = (RelativeLayout) inflater.inflate(R.layout.item_terminal, flip, false); - -		// set the terminal overlay text -		TextView overlay = (TextView) view.findViewById(R.id.terminal_overlay); -		overlay.setText(bridge.host.getNickname()); - -		// and add our terminal view control, using index to place behind overlay -		TerminalView terminal = new TerminalView(ConsoleActivity.this, bridge); -		terminal.setId(R.id.console_flip); -		view.addView(terminal, 0); - -		synchronized (flip) { -			// finally attach to the flipper -			flip.addView(view); -			return flip.getChildCount() - 1; +	public class TerminalPagerAdapter extends PagerAdapter { +		@Override +		public int getCount() { +			if (bound != null) { +				return bound.getBridges().size(); +			} else { +				return 0; +			}  		} -	} -	private int getFlipIndex(TerminalBridge bridge) { -		synchronized (flip) { -			final int children = flip.getChildCount(); -			for (int i = 0; i < children; i++) { -				final View view = flip.getChildAt(i).findViewById(R.id.console_flip); +		@Override +		public Object instantiateItem(ViewGroup container, int position) { +			if (bound == null || bound.getBridges().size() <= position) { +				Log.w(TAG, "Activity not bound when creating TerminalView."); +			} +			TerminalBridge bridge = bound.getBridges().get(position); +			bridge.promptHelper.setHandler(promptHandler); + +			// inflate each terminal view +			RelativeLayout view = (RelativeLayout) inflater.inflate( +					R.layout.item_terminal, container, false); -				if (view == null || !(view instanceof TerminalView)) { -					// How did that happen? -					continue; -				} +			// set the terminal overlay text +			TextView overlay = (TextView) view.findViewById(R.id.terminal_overlay); +			overlay.setText(bridge.host.getNickname()); -				final TerminalView tv = (TerminalView) view; +			// and add our terminal view control, using index to place behind overlay +			final TerminalView terminal = new TerminalView(container.getContext(), bridge); +			terminal.setId(R.id.console_flip); +			view.addView(terminal, 0); + +			// Tag the view with its bridge so it can be retrieved later. +			view.setTag(bridge); + +			container.addView(view); +			overlay.startAnimation(fade_out_delayed); +			return view; +		} -				if (tv.bridge == bridge) { -					return i; +		@Override +		public void destroyItem(ViewGroup container, int position, Object object) { +			final View view = (View) object; + +			container.removeView(view); +		} + +		@Override +		public int getItemPosition(Object object) { +			final View view = (View) object; +			TerminalView terminal = (TerminalView) view.findViewById(R.id.console_flip); +			final HostBean host = terminal.bridge.host; +			int itemIndex = -1; +			int i = 0; +			for (TerminalBridge bridge : bound.getBridges()) { +				if (bridge.host.equals(host)) { +					itemIndex = i; +					break;  				} +				i++; +			} +			if (itemIndex == -1) { +				return POSITION_NONE; +			} else { +				return itemIndex;  			}  		} -		return -1; -	} +		public TerminalBridge getItemAtPosition(int position) { +			return bound.getBridges().get(position); +		} -	/** -	 * Displays the child in the ViewFlipper at the requestedIndex and updates the prompts. -	 * -	 * @param requestedIndex the index of the terminal view to display -	 */ -	private void setDisplayedTerminal(int requestedIndex) { -		synchronized (flip) { -			try { -				// show the requested bridge if found, also fade out overlay -				flip.setDisplayedChild(requestedIndex); -				flip.getCurrentView().findViewById(R.id.terminal_overlay) -						.startAnimation(fade_out_delayed); -			} catch (NullPointerException npe) { -				Log.d(TAG, "View went away when we were about to display it", npe); -			} +		@Override +		public boolean isViewFromObject(View view, Object object) { +			return view == object; +		} -			updatePromptVisible(); -			updateEmptyVisible(); +		@Override +		public CharSequence getPageTitle(int position) { +			return bound.getBridges().get(position).host.getNickname(); +		} + +		public TerminalView getCurrentTerminalView() { +			View currentView = pager.findViewWithTag(adapter.getItemAtPosition(pager.getCurrentItem())); +			if (currentView == null) return null; +			return (TerminalView) currentView.findViewById(R.id.console_flip);  		}  	}  } diff --git a/app/src/main/java/org/connectbot/service/TerminalManager.java b/app/src/main/java/org/connectbot/service/TerminalManager.java index b5d891d..8001561 100644 --- a/app/src/main/java/org/connectbot/service/TerminalManager.java +++ b/app/src/main/java/org/connectbot/service/TerminalManager.java @@ -22,6 +22,7 @@ import java.lang.ref.WeakReference;  import java.security.KeyPair;  import java.security.PrivateKey;  import java.security.PublicKey; +import java.util.ArrayList;  import java.util.Arrays;  import java.util.HashMap;  import java.util.LinkedList; @@ -70,7 +71,7 @@ import android.util.Log;  public class TerminalManager extends Service implements BridgeDisconnectedListener, OnSharedPreferenceChangeListener {  	public final static String TAG = "CB.TerminalManager"; -	private List<TerminalBridge> bridges = new LinkedList<TerminalBridge>(); +	private ArrayList<TerminalBridge> bridges = new ArrayList<TerminalBridge>();  	public Map<HostBean, WeakReference<TerminalBridge>> mHostBridgeMap =  		new HashMap<HostBean, WeakReference<TerminalBridge>>();  	public Map<String, WeakReference<TerminalBridge>> mNicknameBridgeMap = @@ -471,7 +472,7 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen  		}  	} -	public List<TerminalBridge> getBridges() { +	public ArrayList<TerminalBridge> getBridges() {  		return bridges;  	} diff --git a/app/src/main/res/layout/act_console.xml b/app/src/main/res/layout/act_console.xml index cd06e50..b3f5157 100644 --- a/app/src/main/res/layout/act_console.xml +++ b/app/src/main/res/layout/act_console.xml @@ -33,7 +33,7 @@  		android:gravity="center"  		/> -	<ViewFlipper +	<android.support.v4.view.ViewPager  		android:id="@+id/console_flip"  		android:layout_width="fill_parent"  		android:layout_height="fill_parent" @@ -135,7 +135,7 @@  			android:layout_alignParentBottom="true"  			android:layout_alignParentEnd="true"  			android:layout_alignParentRight="true" -			android:src="@+drawable/button_keyboard" +			android:src="@drawable/button_keyboard"  			android:contentDescription="@string/image_description_show_keyboard"  			/> @@ -147,7 +147,7 @@  			android:layout_alignParentStart="true"  			android:layout_alignParentLeft="true"  			android:layout_alignParentBottom="true" -			android:src="@+drawable/button_ctrl" +			android:src="@drawable/button_ctrl"  			android:contentDescription="@string/image_description_toggle_control_character"  			/> @@ -158,7 +158,7 @@  			android:layout_height="wrap_content"  			android:layout_toRightOf="@+id/button_ctrl"  			android:layout_alignParentBottom="true" -			android:src="@+drawable/button_esc" +			android:src="@drawable/button_esc"  			android:contentDescription="@string/image_description_send_escape_character"  			/> @@ -169,7 +169,7 @@        android:layout_height="wrap_content"        android:layout_toRightOf="@+id/button_esc"        android:layout_alignParentBottom="true" -      android:src="@+drawable/button_tab" +      android:src="@drawable/button_tab"        android:contentDescription="@string/image_description_send_tab_character"        /> | 
