Mercurial > 510Connectbot
comparison src/com/five_ten_sg/connectbot/PortForwardListActivity.java @ 0:0ce5cc452d02
initial version
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Thu, 22 May 2014 10:41:19 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:0ce5cc452d02 |
---|---|
1 /* | |
2 * ConnectBot: simple, powerful, open-source SSH client for Android | |
3 * Copyright 2007 Kenny Root, Jeffrey Sharkey | |
4 * | |
5 * Licensed under the Apache License, Version 2.0 (the "License"); | |
6 * you may not use this file except in compliance with the License. | |
7 * You may obtain a copy of the License at | |
8 * | |
9 * http://www.apache.org/licenses/LICENSE-2.0 | |
10 * | |
11 * Unless required by applicable law or agreed to in writing, software | |
12 * distributed under the License is distributed on an "AS IS" BASIS, | |
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 * See the License for the specific language governing permissions and | |
15 * limitations under the License. | |
16 */ | |
17 | |
18 package com.five_ten_sg.connectbot; | |
19 | |
20 import java.util.List; | |
21 | |
22 import com.five_ten_sg.connectbot.bean.HostBean; | |
23 import com.five_ten_sg.connectbot.bean.PortForwardBean; | |
24 import com.five_ten_sg.connectbot.service.TerminalBridge; | |
25 import com.five_ten_sg.connectbot.service.TerminalManager; | |
26 import com.five_ten_sg.connectbot.util.HostDatabase; | |
27 import android.app.AlertDialog; | |
28 import android.app.ListActivity; | |
29 import android.content.ComponentName; | |
30 import android.content.Context; | |
31 import android.content.DialogInterface; | |
32 import android.content.Intent; | |
33 import android.content.ServiceConnection; | |
34 import android.content.res.Resources; | |
35 import android.database.SQLException; | |
36 import android.graphics.Paint; | |
37 import android.os.Bundle; | |
38 import android.os.Handler; | |
39 import android.os.IBinder; | |
40 import android.os.Message; | |
41 import android.util.Log; | |
42 import android.view.ContextMenu; | |
43 import android.view.LayoutInflater; | |
44 import android.view.Menu; | |
45 import android.view.MenuItem; | |
46 import android.view.MenuItem.OnMenuItemClickListener; | |
47 import android.view.View; | |
48 import android.view.ViewGroup; | |
49 import android.widget.AdapterView; | |
50 import android.widget.AdapterView.OnItemClickListener; | |
51 import android.widget.AdapterView.OnItemSelectedListener; | |
52 import android.widget.ArrayAdapter; | |
53 import android.widget.EditText; | |
54 import android.widget.ListView; | |
55 import android.widget.Spinner; | |
56 import android.widget.TextView; | |
57 import android.widget.Toast; | |
58 | |
59 /** | |
60 * List all portForwards for a particular host and provide a way for users to add more portForwards, | |
61 * edit existing portForwards, and delete portForwards. | |
62 * | |
63 * @author Kenny Root | |
64 */ | |
65 public class PortForwardListActivity extends ListActivity { | |
66 public final static String TAG = "ConnectBot.PortForwardListActivity"; | |
67 | |
68 private static final int LISTENER_CYCLE_TIME = 500; | |
69 | |
70 protected HostDatabase hostdb; | |
71 | |
72 private List<PortForwardBean> portForwards; | |
73 | |
74 private ServiceConnection connection = null; | |
75 protected TerminalBridge hostBridge = null; | |
76 protected LayoutInflater inflater = null; | |
77 | |
78 private HostBean host; | |
79 | |
80 @Override | |
81 public void onStart() { | |
82 super.onStart(); | |
83 this.bindService(new Intent(this, TerminalManager.class), connection, Context.BIND_AUTO_CREATE); | |
84 | |
85 if (this.hostdb == null) | |
86 this.hostdb = new HostDatabase(this); | |
87 } | |
88 | |
89 @Override | |
90 public void onStop() { | |
91 super.onStop(); | |
92 this.unbindService(connection); | |
93 | |
94 if (this.hostdb != null) { | |
95 this.hostdb.close(); | |
96 this.hostdb = null; | |
97 } | |
98 } | |
99 | |
100 @Override | |
101 public void onCreate(Bundle icicle) { | |
102 super.onCreate(icicle); | |
103 long hostId = this.getIntent().getLongExtra(Intent.EXTRA_TITLE, -1); | |
104 setContentView(R.layout.act_portforwardlist); | |
105 // connect with hosts database and populate list | |
106 this.hostdb = new HostDatabase(this); | |
107 host = hostdb.findHostById(hostId); | |
108 { | |
109 final String nickname = host != null ? host.getNickname() : null; | |
110 final Resources resources = getResources(); | |
111 | |
112 if (nickname != null) { | |
113 this.setTitle(String.format("%s: %s (%s)", | |
114 resources.getText(R.string.app_name), | |
115 resources.getText(R.string.title_port_forwards_list), | |
116 nickname)); | |
117 } | |
118 else { | |
119 this.setTitle(String.format("%s: %s", | |
120 resources.getText(R.string.app_name), | |
121 resources.getText(R.string.title_port_forwards_list))); | |
122 } | |
123 } | |
124 connection = new ServiceConnection() { | |
125 public void onServiceConnected(ComponentName className, IBinder service) { | |
126 TerminalManager bound = ((TerminalManager.TerminalBinder) service).getService(); | |
127 hostBridge = bound.getConnectedBridge(host); | |
128 updateHandler.sendEmptyMessage(-1); | |
129 } | |
130 public void onServiceDisconnected(ComponentName name) { | |
131 hostBridge = null; | |
132 } | |
133 }; | |
134 this.updateList(); | |
135 this.registerForContextMenu(this.getListView()); | |
136 this.getListView().setOnItemClickListener(new OnItemClickListener() { | |
137 public void onItemClick(AdapterView<?> adapter, View view, int position, long id) { | |
138 ListView lv = PortForwardListActivity.this.getListView(); | |
139 PortForwardBean pfb = (PortForwardBean) lv.getItemAtPosition(position); | |
140 | |
141 if (hostBridge != null) { | |
142 if (pfb.isEnabled()) | |
143 hostBridge.disablePortForward(pfb); | |
144 else { | |
145 if (!hostBridge.enablePortForward(pfb)) | |
146 Toast.makeText(PortForwardListActivity.this, getString(R.string.portforward_problem), Toast.LENGTH_LONG).show(); | |
147 } | |
148 | |
149 updateHandler.sendEmptyMessage(-1); | |
150 } | |
151 } | |
152 }); | |
153 this.inflater = LayoutInflater.from(this); | |
154 } | |
155 | |
156 @Override | |
157 public boolean onCreateOptionsMenu(Menu menu) { | |
158 super.onCreateOptionsMenu(menu); | |
159 MenuItem add = menu.add(R.string.portforward_menu_add); | |
160 add.setIcon(android.R.drawable.ic_menu_add); | |
161 add.setOnMenuItemClickListener(new OnMenuItemClickListener() { | |
162 public boolean onMenuItemClick(MenuItem item) { | |
163 // build dialog to prompt user about updating | |
164 final View portForwardView = inflater.inflate(R.layout.dia_portforward, null, false); | |
165 final EditText destEdit = (EditText) portForwardView.findViewById(R.id.portforward_destination); | |
166 final Spinner typeSpinner = (Spinner)portForwardView.findViewById(R.id.portforward_type); | |
167 typeSpinner.setOnItemSelectedListener(new OnItemSelectedListener() { | |
168 public void onItemSelected(AdapterView<?> value, View view, | |
169 int position, long id) { | |
170 destEdit.setEnabled(position != 2); | |
171 } | |
172 public void onNothingSelected(AdapterView<?> arg0) { | |
173 } | |
174 }); | |
175 new AlertDialog.Builder(PortForwardListActivity.this) | |
176 .setView(portForwardView) | |
177 .setPositiveButton(R.string.portforward_pos, new DialogInterface.OnClickListener() { | |
178 public void onClick(DialogInterface dialog, int which) { | |
179 try { | |
180 final EditText nicknameEdit = (EditText) portForwardView.findViewById(R.id.nickname); | |
181 final EditText sourcePortEdit = (EditText) portForwardView.findViewById(R.id.portforward_source); | |
182 String type = HostDatabase.PORTFORWARD_LOCAL; | |
183 | |
184 switch (typeSpinner.getSelectedItemPosition()) { | |
185 case 0: | |
186 type = HostDatabase.PORTFORWARD_LOCAL; | |
187 break; | |
188 | |
189 case 1: | |
190 type = HostDatabase.PORTFORWARD_REMOTE; | |
191 break; | |
192 | |
193 case 2: | |
194 type = HostDatabase.PORTFORWARD_DYNAMIC5; | |
195 break; | |
196 } | |
197 | |
198 PortForwardBean pfb = new PortForwardBean( | |
199 host != null ? host.getId() : -1, | |
200 nicknameEdit.getText().toString(), type, | |
201 sourcePortEdit.getText().toString(), | |
202 destEdit.getText().toString()); | |
203 | |
204 if (hostBridge != null) { | |
205 hostBridge.addPortForward(pfb); | |
206 hostBridge.enablePortForward(pfb); | |
207 } | |
208 | |
209 if (host != null && !hostdb.savePortForward(pfb)) | |
210 throw new SQLException("Could not save port forward"); | |
211 | |
212 updateHandler.sendEmptyMessage(-1); | |
213 } | |
214 catch (Exception e) { | |
215 Log.e(TAG, "Could not update port forward", e); | |
216 // TODO Show failure dialog. | |
217 } | |
218 } | |
219 }) | |
220 .setNegativeButton(R.string.delete_neg, null).create().show(); | |
221 return true; | |
222 } | |
223 }); | |
224 return true; | |
225 } | |
226 | |
227 @Override | |
228 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { | |
229 // Create menu to handle deleting and editing port forward | |
230 AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; | |
231 final PortForwardBean pfb = (PortForwardBean) this.getListView().getItemAtPosition(info.position); | |
232 menu.setHeaderTitle(pfb.getNickname()); | |
233 MenuItem edit = menu.add(R.string.portforward_edit); | |
234 edit.setOnMenuItemClickListener(new OnMenuItemClickListener() { | |
235 public boolean onMenuItemClick(MenuItem item) { | |
236 final View editTunnelView = inflater.inflate(R.layout.dia_portforward, null, false); | |
237 final Spinner typeSpinner = (Spinner) editTunnelView.findViewById(R.id.portforward_type); | |
238 | |
239 if (HostDatabase.PORTFORWARD_LOCAL.equals(pfb.getType())) | |
240 typeSpinner.setSelection(0); | |
241 else if (HostDatabase.PORTFORWARD_REMOTE.equals(pfb.getType())) | |
242 typeSpinner.setSelection(1); | |
243 else | |
244 typeSpinner.setSelection(2); | |
245 | |
246 final EditText nicknameEdit = (EditText) editTunnelView.findViewById(R.id.nickname); | |
247 nicknameEdit.setText(pfb.getNickname()); | |
248 final EditText sourcePortEdit = (EditText) editTunnelView.findViewById(R.id.portforward_source); | |
249 sourcePortEdit.setText(String.valueOf(pfb.getSourcePort())); | |
250 final EditText destEdit = (EditText) editTunnelView.findViewById(R.id.portforward_destination); | |
251 | |
252 if (HostDatabase.PORTFORWARD_DYNAMIC5.equals(pfb.getType())) { | |
253 destEdit.setEnabled(false); | |
254 } | |
255 else { | |
256 destEdit.setText(String.format("%s:%d", pfb.getDestAddr(), pfb.getDestPort())); | |
257 } | |
258 | |
259 typeSpinner.setOnItemSelectedListener(new OnItemSelectedListener() { | |
260 public void onItemSelected(AdapterView<?> value, View view, | |
261 int position, long id) { | |
262 destEdit.setEnabled(position != 2); | |
263 } | |
264 public void onNothingSelected(AdapterView<?> arg0) { | |
265 } | |
266 }); | |
267 new AlertDialog.Builder(PortForwardListActivity.this) | |
268 .setView(editTunnelView) | |
269 .setPositiveButton(R.string.button_change, new DialogInterface.OnClickListener() { | |
270 public void onClick(DialogInterface dialog, int which) { | |
271 try { | |
272 if (hostBridge != null) | |
273 hostBridge.disablePortForward(pfb); | |
274 | |
275 pfb.setNickname(nicknameEdit.getText().toString()); | |
276 | |
277 switch (typeSpinner.getSelectedItemPosition()) { | |
278 case 0: | |
279 pfb.setType(HostDatabase.PORTFORWARD_LOCAL); | |
280 break; | |
281 | |
282 case 1: | |
283 pfb.setType(HostDatabase.PORTFORWARD_REMOTE); | |
284 break; | |
285 | |
286 case 2: | |
287 pfb.setType(HostDatabase.PORTFORWARD_DYNAMIC5); | |
288 break; | |
289 } | |
290 | |
291 pfb.setSourcePort(Integer.parseInt(sourcePortEdit.getText().toString())); | |
292 pfb.setDest(destEdit.getText().toString()); | |
293 | |
294 // Use the new settings for the existing connection. | |
295 if (hostBridge != null) | |
296 updateHandler.postDelayed(new Runnable() { | |
297 public void run() { | |
298 hostBridge.enablePortForward(pfb); | |
299 updateHandler.sendEmptyMessage(-1); | |
300 } | |
301 }, LISTENER_CYCLE_TIME); | |
302 | |
303 if (!hostdb.savePortForward(pfb)) | |
304 throw new SQLException("Could not save port forward"); | |
305 | |
306 updateHandler.sendEmptyMessage(-1); | |
307 } | |
308 catch (Exception e) { | |
309 Log.e(TAG, "Could not update port forward", e); | |
310 // TODO Show failure dialog. | |
311 } | |
312 } | |
313 }) | |
314 .setNegativeButton(android.R.string.cancel, null).create().show(); | |
315 return true; | |
316 } | |
317 }); | |
318 MenuItem delete = menu.add(R.string.portforward_delete); | |
319 delete.setOnMenuItemClickListener(new OnMenuItemClickListener() { | |
320 public boolean onMenuItemClick(MenuItem item) { | |
321 // prompt user to make sure they really want this | |
322 new AlertDialog.Builder(PortForwardListActivity.this) | |
323 .setMessage(getString(R.string.delete_message, pfb.getNickname())) | |
324 .setPositiveButton(R.string.delete_pos, new DialogInterface.OnClickListener() { | |
325 public void onClick(DialogInterface dialog, int which) { | |
326 try { | |
327 // Delete the port forward from the host if needed. | |
328 if (hostBridge != null) | |
329 hostBridge.removePortForward(pfb); | |
330 | |
331 hostdb.deletePortForward(pfb); | |
332 } | |
333 catch (Exception e) { | |
334 Log.e(TAG, "Could not delete port forward", e); | |
335 } | |
336 | |
337 updateHandler.sendEmptyMessage(-1); | |
338 } | |
339 }) | |
340 .setNegativeButton(R.string.delete_neg, null).create().show(); | |
341 return true; | |
342 } | |
343 }); | |
344 } | |
345 | |
346 protected Handler updateHandler = new Handler() { | |
347 @Override | |
348 public void handleMessage(Message msg) { | |
349 PortForwardListActivity.this.updateList(); | |
350 } | |
351 }; | |
352 | |
353 protected void updateList() { | |
354 if (hostBridge != null) { | |
355 this.portForwards = hostBridge.getPortForwards(); | |
356 } | |
357 else { | |
358 if (this.hostdb == null) return; | |
359 | |
360 this.portForwards = this.hostdb.getPortForwardsForHost(host); | |
361 } | |
362 | |
363 PortForwardAdapter adapter = new PortForwardAdapter(this, portForwards); | |
364 this.setListAdapter(adapter); | |
365 } | |
366 | |
367 class PortForwardAdapter extends ArrayAdapter<PortForwardBean> { | |
368 class ViewHolder { | |
369 public TextView nickname; | |
370 public TextView caption; | |
371 } | |
372 | |
373 private List<PortForwardBean> portForwards; | |
374 | |
375 public PortForwardAdapter(Context context, List<PortForwardBean> portForwards) { | |
376 super(context, R.layout.item_portforward, portForwards); | |
377 this.portForwards = portForwards; | |
378 } | |
379 | |
380 @Override | |
381 public View getView(int position, View convertView, ViewGroup parent) { | |
382 ViewHolder holder; | |
383 | |
384 if (convertView == null) { | |
385 convertView = inflater.inflate(R.layout.item_portforward, null, false); | |
386 holder = new ViewHolder(); | |
387 holder.nickname = (TextView)convertView.findViewById(android.R.id.text1); | |
388 holder.caption = (TextView)convertView.findViewById(android.R.id.text2); | |
389 convertView.setTag(holder); | |
390 } | |
391 else | |
392 holder = (ViewHolder) convertView.getTag(); | |
393 | |
394 PortForwardBean pfb = portForwards.get(position); | |
395 holder.nickname.setText(pfb.getNickname()); | |
396 holder.caption.setText(pfb.getDescription()); | |
397 | |
398 if (hostBridge != null && !pfb.isEnabled()) { | |
399 holder.nickname.setPaintFlags(holder.nickname.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); | |
400 holder.caption.setPaintFlags(holder.caption.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); | |
401 } | |
402 | |
403 return convertView; | |
404 } | |
405 } | |
406 } |