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