Mercurial > 510Connectbot
annotate src/com/five_ten_sg/connectbot/HostEditorActivity.java @ 107:afe6962769b9
use hash map rather than linear search thru arrays
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Wed, 18 Jun 2014 11:43:08 -0700 |
parents | bb27518ac2e9 |
children | 77ac18bc1b2f |
rev | line source |
---|---|
0 | 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.nio.charset.Charset; | |
21 import java.util.Arrays; | |
22 import java.util.HashMap; | |
23 import java.util.LinkedList; | |
24 import java.util.List; | |
25 import java.util.Map; | |
26 import java.util.Map.Entry; | |
27 import java.util.Set; | |
28 | |
29 import com.five_ten_sg.connectbot.bean.HostBean; | |
30 import com.five_ten_sg.connectbot.service.TerminalBridge; | |
31 import com.five_ten_sg.connectbot.service.TerminalManager; | |
32 import com.five_ten_sg.connectbot.util.HostDatabase; | |
33 import com.five_ten_sg.connectbot.util.PubkeyDatabase; | |
34 import android.content.ComponentName; | |
35 import android.content.ContentValues; | |
36 import android.content.Context; | |
37 import android.content.Intent; | |
38 import android.content.ServiceConnection; | |
39 import android.content.SharedPreferences; | |
40 import android.content.SharedPreferences.OnSharedPreferenceChangeListener; | |
41 import android.database.Cursor; | |
42 import android.database.sqlite.SQLiteDatabase; | |
43 import android.os.Bundle; | |
44 import android.os.IBinder; | |
45 import android.preference.CheckBoxPreference; | |
46 import android.preference.ListPreference; | |
47 import android.preference.Preference; | |
48 import android.preference.PreferenceActivity; | |
49 import android.util.Log; | |
50 | |
51 public class HostEditorActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener { | |
52 public class CursorPreferenceHack implements SharedPreferences { | |
53 protected final String table; | |
54 protected final long id; | |
55 | |
56 protected Map<String, String> values = new HashMap<String, String>(); | |
57 // protected Map<String, String> pubkeys = new HashMap<String, String>(); | |
58 | |
59 public CursorPreferenceHack(String table, long id) { | |
60 this.table = table; | |
61 this.id = id; | |
62 cacheValues(); | |
63 } | |
64 | |
65 protected final void cacheValues() { | |
66 // fill a cursor and cache the values locally | |
67 // this makes sure we dont have any floating cursor to dispose later | |
68 SQLiteDatabase db = hostdb.getReadableDatabase(); | |
69 Cursor cursor = db.query(table, null, "_id = ?", | |
70 new String[] { String.valueOf(id) }, null, null, null); | |
71 | |
72 if (cursor.moveToFirst()) { | |
73 for (int i = 0; i < cursor.getColumnCount(); i++) { | |
74 String key = cursor.getColumnName(i); | |
75 | |
76 if (key.equals(HostDatabase.FIELD_HOST_HOSTKEY)) continue; | |
77 | |
78 String value = cursor.getString(i); | |
79 values.put(key, value); | |
80 } | |
81 } | |
82 | |
83 cursor.close(); | |
84 db.close(); | |
85 // db = pubkeydb.getReadableDatabase(); | |
86 // cursor = db.query(PubkeyDatabase.TABLE_PUBKEYS, | |
87 // new String[] { "_id", PubkeyDatabase.FIELD_PUBKEY_NICKNAME }, | |
88 // null, null, null, null, null); | |
89 // | |
90 // if (cursor.moveToFirst()) { | |
91 // do { | |
92 // String pubkeyid = String.valueOf(cursor.getLong(0)); | |
93 // String value = cursor.getString(1); | |
94 // pubkeys.put(pubkeyid, value); | |
95 // } while (cursor.moveToNext()); | |
96 // } | |
97 // | |
98 // cursor.close(); | |
99 // db.close(); | |
100 } | |
101 | |
102 public boolean contains(String key) { | |
103 return values.containsKey(key); | |
104 } | |
105 | |
106 public class Editor implements SharedPreferences.Editor { | |
107 | |
108 private ContentValues update = new ContentValues(); | |
109 | |
110 public SharedPreferences.Editor clear() { | |
111 Log.d(this.getClass().toString(), "clear()"); | |
112 update = new ContentValues(); | |
113 return this; | |
114 } | |
115 | |
116 public boolean commit() { | |
117 //Log.d(this.getClass().toString(), "commit() changes back to database"); | |
118 SQLiteDatabase db = hostdb.getWritableDatabase(); | |
119 db.update(table, update, "_id = ?", new String[] { String.valueOf(id) }); | |
120 db.close(); | |
121 // make sure we refresh the parent cached values | |
122 cacheValues(); | |
123 | |
124 // and update any listeners | |
125 for (OnSharedPreferenceChangeListener listener : listeners) { | |
126 listener.onSharedPreferenceChanged(CursorPreferenceHack.this, null); | |
127 } | |
128 | |
129 return true; | |
130 } | |
131 | |
132 // Gingerbread compatibility | |
133 public void apply() { | |
134 commit(); | |
135 } | |
136 | |
137 public android.content.SharedPreferences.Editor putBoolean(String key, boolean value) { | |
138 return this.putString(key, Boolean.toString(value)); | |
139 } | |
140 | |
141 public android.content.SharedPreferences.Editor putFloat(String key, float value) { | |
142 return this.putString(key, Float.toString(value)); | |
143 } | |
144 | |
145 public android.content.SharedPreferences.Editor putInt(String key, int value) { | |
146 return this.putString(key, Integer.toString(value)); | |
147 } | |
148 | |
149 public android.content.SharedPreferences.Editor putLong(String key, long value) { | |
150 return this.putString(key, Long.toString(value)); | |
151 } | |
152 | |
153 public android.content.SharedPreferences.Editor putString(String key, String value) { | |
154 //Log.d(this.getClass().toString(), String.format("Editor.putString(key=%s, value=%s)", key, value)); | |
155 update.put(key, value); | |
156 return this; | |
157 } | |
158 | |
159 public android.content.SharedPreferences.Editor remove(String key) { | |
160 //Log.d(this.getClass().toString(), String.format("Editor.remove(key=%s)", key)); | |
161 update.remove(key); | |
162 return this; | |
163 } | |
164 | |
165 public android.content.SharedPreferences.Editor putStringSet(String key, Set<String> value) { | |
166 throw new UnsupportedOperationException("HostEditor Prefs do not support Set<String>"); | |
167 } | |
168 } | |
169 | |
170 | |
171 public Editor edit() { | |
172 //Log.d(this.getClass().toString(), "edit()"); | |
173 return new Editor(); | |
174 } | |
175 | |
176 public Map<String, ?> getAll() { | |
177 return values; | |
178 } | |
179 | |
180 public boolean getBoolean(String key, boolean defValue) { | |
181 return Boolean.valueOf(this.getString(key, Boolean.toString(defValue))); | |
182 } | |
183 | |
184 public float getFloat(String key, float defValue) { | |
185 return Float.valueOf(this.getString(key, Float.toString(defValue))); | |
186 } | |
187 | |
188 public int getInt(String key, int defValue) { | |
189 return Integer.valueOf(this.getString(key, Integer.toString(defValue))); | |
190 } | |
191 | |
192 public long getLong(String key, long defValue) { | |
193 return Long.valueOf(this.getString(key, Long.toString(defValue))); | |
194 } | |
195 | |
196 public String getString(String key, String defValue) { | |
197 //Log.d(this.getClass().toString(), String.format("getString(key=%s, defValue=%s)", key, defValue)); | |
198 if (!values.containsKey(key)) return defValue; | |
199 | |
200 return values.get(key); | |
201 } | |
202 | |
203 public Set<String> getStringSet(String key, Set<String> defValue) { | |
204 throw new ClassCastException("HostEditor Prefs do not support Set<String>"); | |
205 } | |
206 | |
207 protected List<OnSharedPreferenceChangeListener> listeners = new LinkedList<OnSharedPreferenceChangeListener>(); | |
208 | |
209 public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) { | |
210 listeners.add(listener); | |
211 } | |
212 | |
213 public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) { | |
214 listeners.remove(listener); | |
215 } | |
216 | |
217 } | |
218 | |
219 @Override | |
220 public SharedPreferences getSharedPreferences(String name, int mode) { | |
221 //Log.d(this.getClass().toString(), String.format("getSharedPreferences(name=%s)", name)); | |
222 return this.pref; | |
223 } | |
224 | |
225 protected static final String TAG = "ConnectBot.HostEditorActivity"; | |
226 | |
227 protected HostDatabase hostdb = null; | |
228 private PubkeyDatabase pubkeydb = null; | |
229 | |
230 private CursorPreferenceHack pref; | |
231 private ServiceConnection connection; | |
232 | |
233 private HostBean host; | |
83
4ccfde0bc506
disable host config items that are not applicable to the host protocol
Carl Byington <carl@five-ten-sg.com>
parents:
0
diff
changeset
|
234 private boolean enableSSHFeatures; |
4ccfde0bc506
disable host config items that are not applicable to the host protocol
Carl Byington <carl@five-ten-sg.com>
parents:
0
diff
changeset
|
235 private boolean enable5250Features; |
4ccfde0bc506
disable host config items that are not applicable to the host protocol
Carl Byington <carl@five-ten-sg.com>
parents:
0
diff
changeset
|
236 private boolean enableAsyncFeatures; |
4ccfde0bc506
disable host config items that are not applicable to the host protocol
Carl Byington <carl@five-ten-sg.com>
parents:
0
diff
changeset
|
237 |
0 | 238 protected TerminalBridge hostBridge; |
239 | |
240 @Override | |
241 public void onCreate(Bundle icicle) { | |
242 super.onCreate(icicle); | |
243 long hostId = this.getIntent().getLongExtra(Intent.EXTRA_TITLE, -1); | |
244 // TODO: we could pass through a specific ContentProvider uri here | |
245 //this.getPreferenceManager().setSharedPreferencesName(uri); | |
246 this.hostdb = new HostDatabase(this); | |
247 this.pubkeydb = new PubkeyDatabase(this); | |
248 host = hostdb.findHostById(hostId); | |
83
4ccfde0bc506
disable host config items that are not applicable to the host protocol
Carl Byington <carl@five-ten-sg.com>
parents:
0
diff
changeset
|
249 enableSSHFeatures = host.isSSH(); |
4ccfde0bc506
disable host config items that are not applicable to the host protocol
Carl Byington <carl@five-ten-sg.com>
parents:
0
diff
changeset
|
250 enable5250Features = host.is5250(); |
4ccfde0bc506
disable host config items that are not applicable to the host protocol
Carl Byington <carl@five-ten-sg.com>
parents:
0
diff
changeset
|
251 enableAsyncFeatures = host.isAsync(); |
0 | 252 connection = new ServiceConnection() { |
253 public void onServiceConnected(ComponentName className, IBinder service) { | |
254 TerminalManager bound = ((TerminalManager.TerminalBinder) service).getService(); | |
255 hostBridge = bound.getConnectedBridge(host); | |
256 } | |
257 public void onServiceDisconnected(ComponentName name) { | |
258 hostBridge = null; | |
259 } | |
260 }; | |
261 this.pref = new CursorPreferenceHack(HostDatabase.TABLE_HOSTS, hostId); | |
262 this.pref.registerOnSharedPreferenceChangeListener(this); | |
263 this.addPreferencesFromResource(R.xml.host_prefs); | |
83
4ccfde0bc506
disable host config items that are not applicable to the host protocol
Carl Byington <carl@five-ten-sg.com>
parents:
0
diff
changeset
|
264 |
4ccfde0bc506
disable host config items that are not applicable to the host protocol
Carl Byington <carl@five-ten-sg.com>
parents:
0
diff
changeset
|
265 // disable all preferences that are not applicable to this host |
88
1c22e6a7efff
convert ctrl keys to virtual keys; use proper android home directory
Carl Byington <carl@five-ten-sg.com>
parents:
83
diff
changeset
|
266 findPreference(HostDatabase.FIELD_HOST_PUBKEYID).setEnabled(enableSSHFeatures); |
83
4ccfde0bc506
disable host config items that are not applicable to the host protocol
Carl Byington <carl@five-ten-sg.com>
parents:
0
diff
changeset
|
267 findPreference(HostDatabase.FIELD_HOST_USEAUTHAGENT).setEnabled(enableSSHFeatures); |
89
bb27518ac2e9
convert ctrl keys to virtual keys; use proper android home directory
Carl Byington <carl@five-ten-sg.com>
parents:
88
diff
changeset
|
268 findPreference(HostDatabase.FIELD_HOST_POSTLOGIN).setEnabled(!enable5250Features); |
83
4ccfde0bc506
disable host config items that are not applicable to the host protocol
Carl Byington <carl@five-ten-sg.com>
parents:
0
diff
changeset
|
269 findPreference(HostDatabase.FIELD_HOST_COMPRESSION).setEnabled(enableSSHFeatures); |
4ccfde0bc506
disable host config items that are not applicable to the host protocol
Carl Byington <carl@five-ten-sg.com>
parents:
0
diff
changeset
|
270 findPreference(HostDatabase.FIELD_HOST_HTTPPROXY).setEnabled(enableAsyncFeatures); |
4ccfde0bc506
disable host config items that are not applicable to the host protocol
Carl Byington <carl@five-ten-sg.com>
parents:
0
diff
changeset
|
271 findPreference(HostDatabase.FIELD_HOST_WANTSESSION).setEnabled(enableSSHFeatures); |
4ccfde0bc506
disable host config items that are not applicable to the host protocol
Carl Byington <carl@five-ten-sg.com>
parents:
0
diff
changeset
|
272 findPreference(HostDatabase.FIELD_HOST_USERNAME).setEnabled(enableSSHFeatures); |
4ccfde0bc506
disable host config items that are not applicable to the host protocol
Carl Byington <carl@five-ten-sg.com>
parents:
0
diff
changeset
|
273 findPreference(HostDatabase.FIELD_HOST_EMULATION).setEnabled(!enable5250Features); |
4ccfde0bc506
disable host config items that are not applicable to the host protocol
Carl Byington <carl@five-ten-sg.com>
parents:
0
diff
changeset
|
274 findPreference(HostDatabase.FIELD_HOST_ENCRYPTION5250).setEnabled(enable5250Features); |
4ccfde0bc506
disable host config items that are not applicable to the host protocol
Carl Byington <carl@five-ten-sg.com>
parents:
0
diff
changeset
|
275 findPreference(HostDatabase.FIELD_HOST_WANTX11FORWARD).setEnabled(enableSSHFeatures); |
4ccfde0bc506
disable host config items that are not applicable to the host protocol
Carl Byington <carl@five-ten-sg.com>
parents:
0
diff
changeset
|
276 findPreference(HostDatabase.FIELD_HOST_X11HOST).setEnabled(enableSSHFeatures); |
4ccfde0bc506
disable host config items that are not applicable to the host protocol
Carl Byington <carl@five-ten-sg.com>
parents:
0
diff
changeset
|
277 findPreference(HostDatabase.FIELD_HOST_X11PORT).setEnabled(enableSSHFeatures); |
4ccfde0bc506
disable host config items that are not applicable to the host protocol
Carl Byington <carl@five-ten-sg.com>
parents:
0
diff
changeset
|
278 |
0 | 279 // add all existing pubkeys to our listpreference for user to choose from |
280 // TODO: may be an issue here when this activity is recycled after adding a new pubkey | |
281 // TODO: should consider moving into onStart, but we dont have a good way of resetting the listpref after filling once | |
88
1c22e6a7efff
convert ctrl keys to virtual keys; use proper android home directory
Carl Byington <carl@five-ten-sg.com>
parents:
83
diff
changeset
|
282 ListPreference pubkeyPref = (ListPreference)findPreference(HostDatabase.FIELD_HOST_PUBKEYID); |
0 | 283 List<CharSequence> pubkeyNicks = new LinkedList<CharSequence> (Arrays.asList(pubkeyPref.getEntries())); |
284 pubkeyNicks.addAll(pubkeydb.allValues(PubkeyDatabase.FIELD_PUBKEY_NICKNAME)); | |
285 pubkeyPref.setEntries(pubkeyNicks.toArray(new CharSequence[pubkeyNicks.size()])); | |
286 List<CharSequence> pubkeyIds = new LinkedList<CharSequence> (Arrays.asList(pubkeyPref.getEntryValues())); | |
287 pubkeyIds.addAll(pubkeydb.allValues("_id")); | |
288 pubkeyPref.setEntryValues(pubkeyIds.toArray(new CharSequence[pubkeyIds.size()])); | |
289 // Populate the character set encoding list with all available | |
88
1c22e6a7efff
convert ctrl keys to virtual keys; use proper android home directory
Carl Byington <carl@five-ten-sg.com>
parents:
83
diff
changeset
|
290 final ListPreference charsetPref = (ListPreference)findPreference(HostDatabase.FIELD_HOST_ENCODING); |
0 | 291 |
292 if (CharsetHolder.isInitialized()) { | |
293 initCharsetPref(charsetPref); | |
294 } | |
295 else { | |
296 String[] currentCharsetPref = new String[1]; | |
297 currentCharsetPref[0] = charsetPref.getValue(); | |
298 charsetPref.setEntryValues(currentCharsetPref); | |
299 charsetPref.setEntries(currentCharsetPref); | |
300 new Thread(new Runnable() { | |
301 public void run() { | |
302 initCharsetPref(charsetPref); | |
303 } | |
304 }).start(); | |
305 } | |
306 | |
307 this.updateSummaries(); | |
308 } | |
309 | |
310 @Override | |
311 public void onStart() { | |
312 super.onStart(); | |
313 bindService(new Intent(this, TerminalManager.class), connection, Context.BIND_AUTO_CREATE); | |
314 | |
315 if (this.hostdb == null) | |
316 this.hostdb = new HostDatabase(this); | |
317 | |
318 if (this.pubkeydb == null) | |
319 this.pubkeydb = new PubkeyDatabase(this); | |
320 } | |
321 | |
322 @Override | |
323 public void onStop() { | |
324 super.onStop(); | |
325 unbindService(connection); | |
326 | |
327 if (this.hostdb != null) { | |
328 this.hostdb.close(); | |
329 this.hostdb = null; | |
330 } | |
331 | |
332 if (this.pubkeydb != null) { | |
333 this.pubkeydb.close(); | |
334 this.pubkeydb = null; | |
335 } | |
336 } | |
337 | |
338 private void updateSummaries() { | |
339 // for all text preferences, set hint as current database value | |
340 for (String key : this.pref.values.keySet()) { | |
341 if (key.equals(HostDatabase.FIELD_HOST_POSTLOGIN)) continue; | |
83
4ccfde0bc506
disable host config items that are not applicable to the host protocol
Carl Byington <carl@five-ten-sg.com>
parents:
0
diff
changeset
|
342 if (key.equals(HostDatabase.FIELD_HOST_EMULATION)) continue; |
89
bb27518ac2e9
convert ctrl keys to virtual keys; use proper android home directory
Carl Byington <carl@five-ten-sg.com>
parents:
88
diff
changeset
|
343 if (key.equals(HostDatabase.FIELD_HOST_MONITOR)) continue; |
0 | 344 |
345 Preference pref = this.findPreference(key); | |
346 | |
347 if (pref == null) continue; | |
348 | |
349 if (pref instanceof CheckBoxPreference) continue; | |
350 | |
351 CharSequence value = this.pref.getString(key, ""); | |
352 | |
353 if (key.equals(HostDatabase.FIELD_HOST_PUBKEYID)) { | |
354 try { | |
355 int pubkeyId = Integer.parseInt((String) value); | |
356 | |
357 if (pubkeyId >= 0) | |
358 pref.setSummary(pubkeydb.getNickname(pubkeyId)); | |
359 else if (pubkeyId == HostDatabase.PUBKEYID_ANY) | |
360 pref.setSummary(R.string.list_pubkeyids_any); | |
361 else if (pubkeyId == HostDatabase.PUBKEYID_NEVER) | |
362 pref.setSummary(R.string.list_pubkeyids_none); | |
363 | |
364 continue; | |
365 } | |
366 catch (NumberFormatException nfe) { | |
367 // Fall through. | |
368 } | |
369 } | |
370 else if (pref instanceof ListPreference) { | |
371 ListPreference listPref = (ListPreference) pref; | |
372 int entryIndex = listPref.findIndexOfValue((String) value); | |
373 | |
374 if (entryIndex >= 0) | |
375 value = listPref.getEntries()[entryIndex]; | |
376 } | |
377 | |
378 pref.setSummary(value); | |
379 } | |
380 } | |
381 | |
382 private void initCharsetPref(final ListPreference charsetPref) { | |
383 charsetPref.setEntryValues(CharsetHolder.getCharsetIds()); | |
384 charsetPref.setEntries(CharsetHolder.getCharsetNames()); | |
385 } | |
386 | |
387 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { | |
388 // update values on changed preference | |
389 this.updateSummaries(); | |
390 | |
391 // Our CursorPreferenceHack always send null keys, so try to set charset anyway | |
392 if (hostBridge != null) | |
393 hostBridge.setCharset(sharedPreferences | |
394 .getString(HostDatabase.FIELD_HOST_ENCODING, HostDatabase.ENCODING_DEFAULT)); | |
395 } | |
396 | |
397 public static class CharsetHolder { | |
398 private static boolean initialized = false; | |
399 | |
400 private static CharSequence[] charsetIds; | |
401 private static CharSequence[] charsetNames; | |
402 | |
403 public static CharSequence[] getCharsetNames() { | |
404 if (charsetNames == null) | |
405 initialize(); | |
406 | |
407 return charsetNames; | |
408 } | |
409 | |
410 public static CharSequence[] getCharsetIds() { | |
411 if (charsetIds == null) | |
412 initialize(); | |
413 | |
414 return charsetIds; | |
415 } | |
416 | |
417 private synchronized static void initialize() { | |
418 if (initialized) | |
419 return; | |
420 | |
421 List<CharSequence> charsetIdsList = new LinkedList<CharSequence>(); | |
422 List<CharSequence> charsetNamesList = new LinkedList<CharSequence>(); | |
423 | |
424 for (Entry<String, Charset> entry : Charset.availableCharsets().entrySet()) { | |
425 Charset c = entry.getValue(); | |
426 | |
427 if (c.canEncode() && c.isRegistered()) { | |
428 String key = entry.getKey(); | |
429 | |
430 if (key.startsWith("cp")) { | |
431 // Custom CP437 charset changes | |
432 charsetIdsList.add("CP437"); | |
433 charsetNamesList.add("CP437"); | |
434 } | |
435 | |
436 charsetIdsList.add(entry.getKey()); | |
437 charsetNamesList.add(c.displayName()); | |
438 } | |
439 } | |
440 | |
441 charsetIds = charsetIdsList.toArray(new CharSequence[charsetIdsList.size()]); | |
442 charsetNames = charsetNamesList.toArray(new CharSequence[charsetNamesList.size()]); | |
443 initialized = true; | |
444 } | |
445 | |
446 public static boolean isInitialized() { | |
447 return initialized; | |
448 } | |
449 } | |
450 } |