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