Mercurial > 510Connectbot
annotate app/src/main/java/com/five_ten_sg/connectbot/service/TerminalManager.java @ 510:7953570e5210
update to ganymed-ssh2 tag 263 and fix hmac-sha2-512
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Wed, 01 Feb 2023 17:55:29 -0700 |
parents | f698820bffdf |
children |
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.service; | |
19 | |
20 import java.io.IOException; | |
21 import java.lang.ref.WeakReference; | |
22 import java.security.KeyPair; | |
23 import java.security.PrivateKey; | |
24 import java.security.PublicKey; | |
25 import java.util.Arrays; | |
26 import java.util.HashMap; | |
27 import java.util.LinkedList; | |
28 import java.util.List; | |
29 import java.util.Map; | |
30 import java.util.Map.Entry; | |
31 import java.util.Timer; | |
32 import java.util.TimerTask; | |
33 | |
34 import com.five_ten_sg.connectbot.R; | |
496
f698820bffdf
add socket2 monitor protocol
Carl Byington <carl@five-ten-sg.com>
parents:
470
diff
changeset
|
35 import com.five_ten_sg.connectbot.ConsoleActivity; |
f698820bffdf
add socket2 monitor protocol
Carl Byington <carl@five-ten-sg.com>
parents:
470
diff
changeset
|
36 import com.five_ten_sg.connectbot.service.TerminalBridge; |
0 | 37 import com.five_ten_sg.connectbot.bean.HostBean; |
38 import com.five_ten_sg.connectbot.bean.PubkeyBean; | |
39 import com.five_ten_sg.connectbot.transport.TransportFactory; | |
40 import com.five_ten_sg.connectbot.util.HostDatabase; | |
41 import com.five_ten_sg.connectbot.util.PreferenceConstants; | |
42 import com.five_ten_sg.connectbot.util.PubkeyDatabase; | |
43 import com.five_ten_sg.connectbot.util.PubkeyUtils; | |
44 import android.app.Service; | |
45 import android.content.Context; | |
46 import android.content.Intent; | |
47 import android.content.SharedPreferences; | |
48 import android.content.SharedPreferences.OnSharedPreferenceChangeListener; | |
49 import android.content.res.AssetFileDescriptor; | |
50 import android.content.res.Configuration; | |
51 import android.content.res.Resources; | |
52 import android.media.AudioManager; | |
53 import android.media.MediaPlayer; | |
54 import android.media.MediaPlayer.OnCompletionListener; | |
55 import android.net.Uri; | |
56 import android.os.Binder; | |
57 import android.os.Handler; | |
58 import android.os.IBinder; | |
59 import android.os.Message; | |
60 import android.os.Vibrator; | |
61 import android.preference.PreferenceManager; | |
62 import android.util.Log; | |
63 | |
64 /** | |
65 * Manager for SSH connections that runs as a service. This service holds a list | |
66 * of currently connected SSH bridges that are ready for connection up to a GUI | |
67 * if needed. | |
68 * | |
69 * @author jsharkey | |
70 */ | |
71 public class TerminalManager extends Service implements BridgeDisconnectedListener, OnSharedPreferenceChangeListener { | |
72 public final static String TAG = "ConnectBot.TerminalManager"; | |
73 | |
74 public List<TerminalBridge> bridges = new LinkedList<TerminalBridge>(); | |
75 public Map<HostBean, WeakReference<TerminalBridge>> mHostBridgeMap = | |
76 new HashMap<HostBean, WeakReference<TerminalBridge>>(); | |
77 public Map<String, WeakReference<TerminalBridge>> mNicknameBridgeMap = | |
78 new HashMap<String, WeakReference<TerminalBridge>>(); | |
79 | |
496
f698820bffdf
add socket2 monitor protocol
Carl Byington <carl@five-ten-sg.com>
parents:
470
diff
changeset
|
80 public ConsoleActivity activity = null; |
f698820bffdf
add socket2 monitor protocol
Carl Byington <carl@five-ten-sg.com>
parents:
470
diff
changeset
|
81 |
0 | 82 public TerminalBridge defaultBridge = null; |
83 | |
84 public List<HostBean> disconnected = new LinkedList<HostBean>(); | |
85 | |
86 public Handler disconnectHandler = null; | |
87 | |
88 public Map<String, KeyHolder> loadedKeypairs = new HashMap<String, KeyHolder>(); | |
89 | |
90 public Resources res; | |
91 | |
92 public HostDatabase hostdb; | |
93 public PubkeyDatabase pubkeydb; | |
94 | |
95 protected SharedPreferences prefs; | |
96 | |
97 final private IBinder binder = new TerminalBinder(); | |
98 | |
99 private ConnectivityReceiver connectivityManager; | |
100 private ConnectionNotifier connectionNotifier = new ConnectionNotifier(); | |
101 | |
102 private MediaPlayer mediaPlayer; | |
103 | |
104 private Timer pubkeyTimer; | |
105 | |
106 private Timer idleTimer; | |
107 private final long IDLE_TIMEOUT = 300000; // 5 minutes | |
108 | |
109 private Vibrator vibrator; | |
110 private volatile boolean wantKeyVibration; | |
111 public static final long VIBRATE_DURATION = 30; | |
112 | |
470
2cc170e3fc9b
audible bell checkbox enables/disables bell volume setting; monitor init string is now a url socket://target/initstring
Carl Byington <carl@five-ten-sg.com>
parents:
438
diff
changeset
|
113 private boolean wantBell; |
0 | 114 private boolean wantBellVibration; |
115 | |
116 private boolean resizeAllowed = true; | |
117 | |
118 private int fullScreen = 0; | |
119 | |
120 private boolean savingKeys; | |
121 | |
122 protected List<WeakReference<TerminalBridge>> mPendingReconnect | |
123 = new LinkedList<WeakReference<TerminalBridge>>(); | |
124 | |
125 public boolean hardKeyboardHidden; | |
126 | |
127 @Override | |
128 public void onCreate() { | |
129 Log.i(TAG, "Starting service"); | |
130 prefs = PreferenceManager.getDefaultSharedPreferences(this); | |
131 prefs.registerOnSharedPreferenceChangeListener(this); | |
132 res = getResources(); | |
133 pubkeyTimer = new Timer("pubkeyTimer", true); | |
134 hostdb = new HostDatabase(this); | |
135 pubkeydb = new PubkeyDatabase(this); | |
136 // load all marked pubkeys into memory | |
137 updateSavingKeys(); | |
138 List<PubkeyBean> pubkeys = pubkeydb.getAllStartPubkeys(); | |
139 | |
140 for (PubkeyBean pubkey : pubkeys) { | |
141 try { | |
142 PrivateKey privKey = PubkeyUtils.decodePrivate(pubkey.getPrivateKey(), pubkey.getType()); | |
143 PublicKey pubKey = PubkeyUtils.decodePublic(pubkey.getPublicKey(), pubkey.getType()); | |
144 KeyPair pair = new KeyPair(pubKey, privKey); | |
145 addKey(pubkey, pair); | |
146 } | |
147 catch (Exception e) { | |
148 Log.d(TAG, String.format("Problem adding key '%s' to in-memory cache", pubkey.getNickname()), e); | |
149 } | |
150 } | |
151 | |
152 vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE); | |
153 wantKeyVibration = prefs.getBoolean(PreferenceConstants.BUMPY_ARROWS, true); | |
470
2cc170e3fc9b
audible bell checkbox enables/disables bell volume setting; monitor init string is now a url socket://target/initstring
Carl Byington <carl@five-ten-sg.com>
parents:
438
diff
changeset
|
154 wantBell = prefs.getBoolean(PreferenceConstants.BELL, true); |
0 | 155 wantBellVibration = prefs.getBoolean(PreferenceConstants.BELL_VIBRATE, true); |
470
2cc170e3fc9b
audible bell checkbox enables/disables bell volume setting; monitor init string is now a url socket://target/initstring
Carl Byington <carl@five-ten-sg.com>
parents:
438
diff
changeset
|
156 if (wantBell) enableMediaPlayer(); |
0 | 157 hardKeyboardHidden = (res.getConfiguration().hardKeyboardHidden == |
158 Configuration.HARDKEYBOARDHIDDEN_YES); | |
159 final boolean lockingWifi = prefs.getBoolean(PreferenceConstants.WIFI_LOCK, true); | |
160 connectivityManager = new ConnectivityReceiver(this, lockingWifi); | |
161 } | |
162 | |
163 private void updateSavingKeys() { | |
164 savingKeys = prefs.getBoolean(PreferenceConstants.MEMKEYS, true); | |
165 } | |
166 | |
167 @Override | |
168 public void onDestroy() { | |
169 Log.i(TAG, "Destroying service"); | |
170 disconnectAll(true); | |
171 | |
172 if (hostdb != null) { | |
173 hostdb.close(); | |
174 hostdb = null; | |
175 } | |
176 | |
177 if (pubkeydb != null) { | |
178 pubkeydb.close(); | |
179 pubkeydb = null; | |
180 } | |
181 | |
182 synchronized (this) { | |
183 if (idleTimer != null) | |
184 idleTimer.cancel(); | |
185 | |
186 if (pubkeyTimer != null) | |
187 pubkeyTimer.cancel(); | |
188 } | |
189 | |
190 connectivityManager.cleanup(); | |
191 connectionNotifier.hideRunningNotification(this); | |
192 disableMediaPlayer(); | |
193 } | |
194 | |
195 /** | |
196 * Disconnect all currently connected bridges. | |
197 */ | |
198 private void disconnectAll(final boolean immediate) { | |
199 disconnectAll(immediate, false); | |
200 } | |
201 | |
202 /** | |
203 * Disconnect all currently connected bridges. | |
204 */ | |
205 private void disconnectAll(final boolean immediate, boolean onlyRemote) { | |
206 TerminalBridge[] tmpBridges = null; | |
207 | |
208 synchronized (bridges) { | |
209 if (bridges.size() > 0) { | |
210 tmpBridges = bridges.toArray(new TerminalBridge[bridges.size()]); | |
211 } | |
212 } | |
213 | |
214 if (tmpBridges != null) { | |
215 // disconnect and dispose of any existing bridges | |
216 for (int i = 0; i < tmpBridges.length; i++) { | |
217 if (!onlyRemote || !(tmpBridges[i].transport instanceof com.five_ten_sg.connectbot.transport.Local)) | |
218 tmpBridges[i].dispatchDisconnect(immediate); | |
219 } | |
220 } | |
221 } | |
222 | |
223 /** | |
224 * Open a new SSH session using the given parameters. | |
225 */ | |
226 private TerminalBridge openConnection(HostBean host) throws IllegalArgumentException, IOException { | |
227 // throw exception if terminal already open | |
228 if (getConnectedBridge(host) != null) { | |
229 throw new IllegalArgumentException("Connection already open for that nickname"); | |
230 } | |
231 | |
94
e3b83c4f02f1
remove 5250 configuration
Carl Byington <carl@five-ten-sg.com>
parents:
73
diff
changeset
|
232 TerminalBridge bridge = new TerminalBridge(this, host, getApplicationInfo().dataDir); |
0 | 233 bridge.setOnDisconnectedListener(this); |
234 bridge.startConnection(); | |
235 | |
236 synchronized (bridges) { | |
237 bridges.add(bridge); | |
238 WeakReference<TerminalBridge> wr = new WeakReference<TerminalBridge> (bridge); | |
239 mHostBridgeMap.put(bridge.host, wr); | |
240 mNicknameBridgeMap.put(bridge.host.getNickname(), wr); | |
241 } | |
242 | |
243 synchronized (disconnected) { | |
244 disconnected.remove(bridge.host); | |
245 } | |
246 | |
247 if (bridge.isUsingNetwork()) { | |
248 connectivityManager.incRef(); | |
249 } | |
250 | |
251 if (prefs.getBoolean(PreferenceConstants.CONNECTION_PERSIST, true)) { | |
252 connectionNotifier.showRunningNotification(this); | |
253 } | |
254 | |
255 // also update database with new connected time | |
256 touchHost(host); | |
257 return bridge; | |
258 } | |
259 | |
260 public String getEmulation() { | |
73
accf93be8c12
update documentation; use xterm-256color as default terminal type
Carl Byington <carl@five-ten-sg.com>
parents:
0
diff
changeset
|
261 return prefs.getString(PreferenceConstants.EMULATION, "xterm-256color"); |
0 | 262 } |
263 | |
264 public int getScrollback() { | |
265 int scrollback = 140; | |
266 | |
267 try { | |
268 scrollback = Integer.parseInt(prefs.getString(PreferenceConstants.SCROLLBACK, "140")); | |
269 } | |
270 catch (Exception e) { | |
271 } | |
272 | |
273 return scrollback; | |
274 } | |
275 | |
276 /** | |
277 * Open a new connection by reading parameters from the given URI. Follows | |
278 * format specified by an individual transport. | |
279 */ | |
280 public TerminalBridge openConnection(Uri uri) throws Exception { | |
281 HostBean host = TransportFactory.findHost(hostdb, uri); | |
282 | |
283 if (host == null) | |
284 host = TransportFactory.getTransport(uri.getScheme()).createHost(uri); | |
285 | |
286 return openConnection(host); | |
287 } | |
288 | |
289 /** | |
290 * Update the last-connected value for the given nickname by passing through | |
291 * to {@link HostDatabase}. | |
292 */ | |
293 private void touchHost(HostBean host) { | |
294 hostdb.touchHost(host); | |
295 } | |
296 | |
297 /** | |
298 * Find a connected {@link TerminalBridge} with the given HostBean. | |
299 * | |
300 * @param host the HostBean to search for | |
301 * @return TerminalBridge that uses the HostBean | |
302 */ | |
303 public TerminalBridge getConnectedBridge(HostBean host) { | |
304 WeakReference<TerminalBridge> wr = mHostBridgeMap.get(host); | |
305 | |
306 if (wr != null) { | |
307 return wr.get(); | |
308 } | |
309 else { | |
310 return null; | |
311 } | |
312 } | |
313 | |
314 /** | |
315 * Find a connected {@link TerminalBridge} using its nickname. | |
316 * | |
317 * @param nickname | |
318 * @return TerminalBridge that matches nickname | |
319 */ | |
320 public TerminalBridge getConnectedBridge(final String nickname) { | |
321 if (nickname == null) { | |
322 return null; | |
323 } | |
324 | |
325 WeakReference<TerminalBridge> wr = mNicknameBridgeMap.get(nickname); | |
326 | |
327 if (wr != null) { | |
328 return wr.get(); | |
329 } | |
330 else { | |
331 return null; | |
332 } | |
333 } | |
334 | |
335 /** | |
336 * Called by child bridge when somehow it's been disconnected. | |
337 */ | |
338 public void onDisconnected(TerminalBridge bridge) { | |
339 boolean shouldHideRunningNotification = false; | |
340 | |
341 synchronized (bridges) { | |
342 // remove this bridge from our list | |
343 bridges.remove(bridge); | |
344 mHostBridgeMap.remove(bridge.host); | |
345 mNicknameBridgeMap.remove(bridge.host.getNickname()); | |
346 | |
347 if (bridge.isUsingNetwork()) { | |
348 connectivityManager.decRef(); | |
349 } | |
350 | |
351 if (bridges.size() == 0 && | |
352 mPendingReconnect.size() == 0) { | |
353 shouldHideRunningNotification = true; | |
354 } | |
355 } | |
356 | |
357 synchronized (disconnected) { | |
358 disconnected.add(bridge.host); | |
359 } | |
360 | |
361 if (shouldHideRunningNotification) { | |
362 connectionNotifier.hideRunningNotification(this); | |
363 } | |
364 | |
365 // pass notification back up to gui | |
366 if (disconnectHandler != null) | |
367 Message.obtain(disconnectHandler, -1, bridge).sendToTarget(); | |
368 } | |
369 | |
370 public boolean isKeyLoaded(String nickname) { | |
371 return loadedKeypairs.containsKey(nickname); | |
372 } | |
373 | |
374 public void addKey(PubkeyBean pubkey, KeyPair pair) { | |
375 addKey(pubkey, pair, false); | |
376 } | |
377 | |
378 public void addKey(PubkeyBean pubkey, KeyPair pair, boolean force) { | |
379 if (!savingKeys && !force) | |
380 return; | |
381 | |
382 removeKey(pubkey.getNickname()); | |
383 byte[] sshPubKey = PubkeyUtils.extractOpenSSHPublic(pair); | |
384 KeyHolder keyHolder = new KeyHolder(); | |
385 keyHolder.bean = pubkey; | |
386 keyHolder.pair = pair; | |
387 keyHolder.openSSHPubkey = sshPubKey; | |
388 loadedKeypairs.put(pubkey.getNickname(), keyHolder); | |
389 | |
390 if (pubkey.getLifetime() > 0) { | |
391 final String nickname = pubkey.getNickname(); | |
392 pubkeyTimer.schedule(new TimerTask() { | |
393 @Override | |
394 public void run() { | |
395 Log.d(TAG, "Unloading from memory key: " + nickname); | |
396 removeKey(nickname); | |
397 } | |
398 }, pubkey.getLifetime() * 1000); | |
399 } | |
400 | |
401 Log.d(TAG, String.format("Added key '%s' to in-memory cache", pubkey.getNickname())); | |
402 } | |
403 | |
404 public boolean removeKey(String nickname) { | |
388
ebcb4aea03ec
fix documentation typos
Carl Byington <carl@five-ten-sg.com>
parents:
94
diff
changeset
|
405 Log.d(TAG, String.format("Removed key '%s' from in-memory cache", nickname)); |
0 | 406 return loadedKeypairs.remove(nickname) != null; |
407 } | |
408 | |
409 public boolean removeKey(byte[] publicKey) { | |
410 String nickname = null; | |
411 | |
412 for (Entry<String, KeyHolder> entry : loadedKeypairs.entrySet()) { | |
413 if (Arrays.equals(entry.getValue().openSSHPubkey, publicKey)) { | |
414 nickname = entry.getKey(); | |
415 break; | |
416 } | |
417 } | |
418 | |
419 if (nickname != null) { | |
420 Log.d(TAG, String.format("Removed key '%s' to in-memory cache", nickname)); | |
421 return removeKey(nickname); | |
422 } | |
423 else | |
424 return false; | |
425 } | |
426 | |
427 public KeyPair getKey(String nickname) { | |
428 if (loadedKeypairs.containsKey(nickname)) { | |
429 KeyHolder keyHolder = loadedKeypairs.get(nickname); | |
430 return keyHolder.pair; | |
431 } | |
432 else | |
433 return null; | |
434 } | |
435 | |
436 public KeyPair getKey(byte[] publicKey) { | |
437 for (KeyHolder keyHolder : loadedKeypairs.values()) { | |
438 if (Arrays.equals(keyHolder.openSSHPubkey, publicKey)) | |
439 return keyHolder.pair; | |
440 } | |
441 | |
442 return null; | |
443 } | |
444 | |
445 public String getKeyNickname(byte[] publicKey) { | |
446 for (Entry<String, KeyHolder> entry : loadedKeypairs.entrySet()) { | |
447 if (Arrays.equals(entry.getValue().openSSHPubkey, publicKey)) | |
448 return entry.getKey(); | |
449 } | |
450 | |
451 return null; | |
452 } | |
453 | |
454 private void stopWithDelay() { | |
455 // TODO add in a way to check whether keys loaded are encrypted and only | |
456 // set timer when we have an encrypted key loaded | |
457 if (loadedKeypairs.size() > 0) { | |
458 synchronized (this) { | |
459 if (idleTimer == null) | |
460 idleTimer = new Timer("idleTimer", true); | |
461 | |
462 idleTimer.schedule(new IdleTask(), IDLE_TIMEOUT); | |
463 } | |
464 } | |
465 else { | |
466 Log.d(TAG, "Stopping service immediately"); | |
467 stopSelf(); | |
468 } | |
469 } | |
470 | |
471 protected void stopNow() { | |
472 if (bridges.size() == 0) { | |
473 stopSelf(); | |
474 } | |
475 } | |
476 | |
477 private synchronized void stopIdleTimer() { | |
478 if (idleTimer != null) { | |
479 idleTimer.cancel(); | |
480 idleTimer = null; | |
481 } | |
482 } | |
483 | |
484 public class TerminalBinder extends Binder { | |
485 public TerminalManager getService() { | |
486 return TerminalManager.this; | |
487 } | |
488 } | |
489 | |
490 @Override | |
491 public IBinder onBind(Intent intent) { | |
492 Log.i(TAG, "Someone bound to TerminalManager"); | |
493 setResizeAllowed(true); | |
494 stopIdleTimer(); | |
495 // Make sure we stay running to maintain the bridges | |
496 startService(new Intent(this, TerminalManager.class)); | |
497 return binder; | |
498 } | |
499 | |
500 @Override | |
501 public int onStartCommand(Intent intent, int flags, int startId) { | |
502 /* | |
503 * We want this service to continue running until it is explicitly | |
504 * stopped, so return sticky. | |
505 */ | |
506 return START_STICKY; | |
507 } | |
508 | |
509 @Override | |
510 public void onRebind(Intent intent) { | |
511 super.onRebind(intent); | |
512 setResizeAllowed(true); | |
513 Log.i(TAG, "Someone rebound to TerminalManager"); | |
514 stopIdleTimer(); | |
515 } | |
516 | |
517 @Override | |
518 public boolean onUnbind(Intent intent) { | |
519 Log.i(TAG, "Someone unbound from TerminalManager"); | |
520 setResizeAllowed(true); | |
521 | |
522 if (bridges.size() == 0) { | |
523 stopWithDelay(); | |
524 } | |
525 | |
526 return true; | |
527 } | |
528 | |
529 private class IdleTask extends TimerTask { | |
530 /* (non-Javadoc) | |
531 * @see java.util.TimerTask#run() | |
532 */ | |
533 @Override | |
534 public void run() { | |
535 Log.d(TAG, String.format("Stopping service after timeout of ~%d seconds", IDLE_TIMEOUT / 1000)); | |
536 TerminalManager.this.stopNow(); | |
537 } | |
538 } | |
539 | |
540 public void tryKeyVibrate() { | |
541 if (wantKeyVibration) | |
542 vibrate(); | |
543 } | |
544 | |
545 private void vibrate() { | |
546 if (vibrator != null) | |
547 vibrator.vibrate(VIBRATE_DURATION); | |
548 } | |
549 | |
550 private void enableMediaPlayer() { | |
551 mediaPlayer = new MediaPlayer(); | |
552 float volume = prefs.getFloat(PreferenceConstants.BELL_VOLUME, | |
553 PreferenceConstants.DEFAULT_BELL_VOLUME); | |
554 mediaPlayer.setAudioStreamType(AudioManager.STREAM_NOTIFICATION); | |
555 mediaPlayer.setOnCompletionListener(new BeepListener()); | |
556 AssetFileDescriptor file = res.openRawResourceFd(R.raw.bell); | |
557 | |
558 try { | |
559 mediaPlayer.setDataSource(file.getFileDescriptor(), file | |
560 .getStartOffset(), file.getLength()); | |
561 file.close(); | |
562 mediaPlayer.setVolume(volume, volume); | |
563 mediaPlayer.prepare(); | |
564 } | |
565 catch (IOException e) { | |
566 Log.e(TAG, "Error setting up bell media player", e); | |
567 } | |
568 } | |
569 | |
570 private void disableMediaPlayer() { | |
571 if (mediaPlayer != null) { | |
572 mediaPlayer.release(); | |
573 mediaPlayer = null; | |
574 } | |
575 } | |
576 | |
577 public void playBeep() { | |
578 if (mediaPlayer != null) | |
579 mediaPlayer.start(); | |
580 | |
581 if (wantBellVibration) | |
582 vibrate(); | |
583 } | |
584 | |
585 private static class BeepListener implements OnCompletionListener { | |
586 public void onCompletion(MediaPlayer mp) { | |
587 mp.seekTo(0); | |
588 } | |
589 } | |
590 | |
591 /** | |
592 * Send system notification to user for a certain host. When user selects | |
593 * the notification, it will bring them directly to the ConsoleActivity | |
594 * displaying the host. | |
595 * | |
596 * @param host | |
597 */ | |
598 public void sendActivityNotification(HostBean host) { | |
599 if (!prefs.getBoolean(PreferenceConstants.BELL_NOTIFICATION, false)) | |
600 return; | |
601 | |
602 connectionNotifier.showActivityNotification(this, host); | |
603 } | |
604 | |
605 /* (non-Javadoc) | |
606 * @see android.content.SharedPreferences.OnSharedPreferenceChangeListener#onSharedPreferenceChanged(android.content.SharedPreferences, java.lang.String) | |
607 */ | |
608 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, | |
609 String key) { | |
610 if (PreferenceConstants.BELL.equals(key)) { | |
470
2cc170e3fc9b
audible bell checkbox enables/disables bell volume setting; monitor init string is now a url socket://target/initstring
Carl Byington <carl@five-ten-sg.com>
parents:
438
diff
changeset
|
611 wantBell = sharedPreferences.getBoolean(PreferenceConstants.BELL, true); |
0 | 612 |
470
2cc170e3fc9b
audible bell checkbox enables/disables bell volume setting; monitor init string is now a url socket://target/initstring
Carl Byington <carl@five-ten-sg.com>
parents:
438
diff
changeset
|
613 if (wantBell && mediaPlayer == null) |
0 | 614 enableMediaPlayer(); |
470
2cc170e3fc9b
audible bell checkbox enables/disables bell volume setting; monitor init string is now a url socket://target/initstring
Carl Byington <carl@five-ten-sg.com>
parents:
438
diff
changeset
|
615 else if (!wantBell && mediaPlayer != null) |
0 | 616 disableMediaPlayer(); |
617 } | |
618 else if (PreferenceConstants.BELL_VOLUME.equals(key)) { | |
619 if (mediaPlayer != null) { | |
620 float volume = sharedPreferences.getFloat( | |
621 PreferenceConstants.BELL_VOLUME, | |
622 PreferenceConstants.DEFAULT_BELL_VOLUME); | |
623 mediaPlayer.setVolume(volume, volume); | |
624 } | |
625 } | |
626 else if (PreferenceConstants.BELL_VIBRATE.equals(key)) { | |
627 wantBellVibration = sharedPreferences.getBoolean( | |
628 PreferenceConstants.BELL_VIBRATE, true); | |
629 } | |
630 else if (PreferenceConstants.BUMPY_ARROWS.equals(key)) { | |
631 wantKeyVibration = sharedPreferences.getBoolean( | |
632 PreferenceConstants.BUMPY_ARROWS, true); | |
633 } | |
634 else if (PreferenceConstants.WIFI_LOCK.equals(key)) { | |
635 final boolean lockingWifi = prefs.getBoolean(PreferenceConstants.WIFI_LOCK, true); | |
636 connectivityManager.setWantWifiLock(lockingWifi); | |
637 } | |
638 else if (PreferenceConstants.MEMKEYS.equals(key)) { | |
639 updateSavingKeys(); | |
640 } | |
641 } | |
642 | |
643 /** | |
644 * Allow {@link TerminalBridge} to resize when the parent has changed. | |
645 * @param resizeAllowed | |
646 */ | |
647 public void setResizeAllowed(boolean resizeAllowed) { | |
648 this.resizeAllowed = resizeAllowed; | |
649 } | |
650 | |
651 public boolean isResizeAllowed() { | |
652 return resizeAllowed; | |
653 } | |
654 | |
655 public void setFullScreen(int fullScreen) { | |
656 this.fullScreen = fullScreen; | |
657 } | |
658 | |
659 public int getFullScreen() { | |
660 return this.fullScreen; | |
661 } | |
662 | |
663 public static class KeyHolder { | |
664 public PubkeyBean bean; | |
665 public KeyPair pair; | |
666 public byte[] openSSHPubkey; | |
667 } | |
668 | |
669 /** | |
670 * Called when connectivity to the network is lost and it doesn't appear | |
671 * we'll be getting a different connection any time soon. | |
672 */ | |
673 public void onConnectivityLost() { | |
674 final Thread t = new Thread() { | |
675 @Override | |
676 public void run() { | |
677 disconnectAll(false, true); | |
678 } | |
679 }; | |
680 t.setName("Disconnector"); | |
681 t.start(); | |
682 } | |
683 | |
684 /** | |
685 * Called when connectivity to the network is restored. | |
686 */ | |
687 public void onConnectivityRestored() { | |
688 final Thread t = new Thread() { | |
689 @Override | |
690 public void run() { | |
691 reconnectPending(); | |
692 } | |
693 }; | |
694 t.setName("Reconnector"); | |
695 t.start(); | |
696 } | |
697 | |
698 /** | |
699 * Insert request into reconnect queue to be executed either immediately | |
700 * or later when connectivity is restored depending on whether we're | |
701 * currently connected. | |
702 * | |
703 * @param bridge the TerminalBridge to reconnect when possible | |
704 */ | |
705 public void requestReconnect(TerminalBridge bridge) { | |
706 synchronized (mPendingReconnect) { | |
707 mPendingReconnect.add(new WeakReference<TerminalBridge> (bridge)); | |
708 | |
709 if (!bridge.isUsingNetwork() || | |
710 connectivityManager.isConnected()) { | |
711 reconnectPending(); | |
712 } | |
713 } | |
714 } | |
715 | |
716 /** | |
717 * Reconnect all bridges that were pending a reconnect when connectivity | |
718 * was lost. | |
719 */ | |
720 private void reconnectPending() { | |
721 synchronized (mPendingReconnect) { | |
722 for (WeakReference<TerminalBridge> ref : mPendingReconnect) { | |
723 TerminalBridge bridge = ref.get(); | |
724 | |
725 if (bridge == null) { | |
726 continue; | |
727 } | |
728 | |
729 bridge.startConnection(); | |
730 } | |
731 | |
732 mPendingReconnect.clear(); | |
733 } | |
734 } | |
735 } |