/** Attempts to form a connection to the user-selected host. */ public static void connectToHost( String username, String authToken, String hostJid, String hostId, String hostPubkey, Runnable successCallback) { synchronized (JniInterface.class) { if (!sLoaded) return; if (sConnected) { disconnectFromHost(); } } sSuccessCallback = successCallback; SharedPreferences prefs = sContext.getPreferences(Activity.MODE_PRIVATE); nativeConnect( username, authToken, hostJid, hostId, hostPubkey, prefs.getString(hostId + "_id", ""), prefs.getString(hostId + "_secret", "")); sConnected = true; }
/** Called whenever an action bar button is pressed. */ @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.actionbar_keyboard: ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)).toggleSoftInput(0, 0); return true; case R.id.actionbar_hide: hideActionBar(); return true; case R.id.actionbar_disconnect: JniInterface.disconnectFromHost(); return true; case R.id.actionbar_send_ctrl_alt_del: { int[] keys = { KeyEvent.KEYCODE_CTRL_LEFT, KeyEvent.KEYCODE_ALT_LEFT, KeyEvent.KEYCODE_FORWARD_DEL, }; for (int key : keys) { JniInterface.keyboardAction(key, true); } for (int key : keys) { JniInterface.keyboardAction(key, false); } } return true; default: return super.onOptionsItemSelected(item); } }
/** Called whenever an action bar button is pressed. */ @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); mActivityLifecycleListener.onActivityOptionsItemSelected(this, item); // Whenever a user selects an option from the ActionBar, reset the auto-hide timer. startActionBarAutoHideTimer(); if (id == R.id.actionbar_cardboard) { onCardboardItemSelected(); return true; } if (id == R.id.actionbar_keyboard) { ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)).toggleSoftInput(0, 0); return true; } if (id == R.id.actionbar_hide) { hideActionBar(); return true; } if (id == R.id.actionbar_disconnect || id == android.R.id.home) { JniInterface.disconnectFromHost(); return true; } if (id == R.id.actionbar_send_ctrl_alt_del) { int[] keys = { KeyEvent.KEYCODE_CTRL_LEFT, KeyEvent.KEYCODE_ALT_LEFT, KeyEvent.KEYCODE_FORWARD_DEL, }; for (int key : keys) { JniInterface.sendKeyEvent(0, key, true); } for (int key : keys) { JniInterface.sendKeyEvent(0, key, false); } return true; } if (id == R.id.actionbar_help) { HelpActivity.launch(this, HELP_URL); return true; } return super.onOptionsItemSelected(item); }
/** * Called once when a keyboard key is pressed, then again when that same key is released. This is * not guaranteed to be notified of all soft keyboard events: certian keyboards might not call it * at all, while others might skip it in certain situations (e.g. swipe input). */ @Override public boolean dispatchKeyEvent(KeyEvent event) { int keyCode = event.getKeyCode(); // Dispatch the back button to the system to handle navigation if (keyCode == KeyEvent.KEYCODE_BACK) { JniInterface.disconnectFromHost(); return super.dispatchKeyEvent(event); } boolean pressed = event.getAction() == KeyEvent.ACTION_DOWN; // Physical keyboard must work as if it is connected to the remote host // and so events coming from physical keyboard never generate text // events. Also scan codes must be used instead of key code, so that // the keyboard layout selected on the client doesn't affect the key // codes sent to the host. if (event.getDeviceId() != KeyCharacterMap.VIRTUAL_KEYBOARD) { return JniInterface.sendKeyEvent(event.getScanCode(), 0, pressed); } // Events received from software keyboards generate TextEvent in two // cases: // 1. This is an ACTION_MULTIPLE event. // 2. Ctrl, Alt and Meta are not pressed. // This ensures that on-screen keyboard always injects input that // correspond to what user sees on the screen, while physical keyboard // acts as if it is connected to the remote host. if (event.getAction() == KeyEvent.ACTION_MULTIPLE) { JniInterface.sendTextEvent(event.getCharacters()); return true; } // For Enter getUnicodeChar() returns 10 (line feed), but we still // want to send it as KeyEvent. int unicode = keyCode != KeyEvent.KEYCODE_ENTER ? event.getUnicodeChar() : 0; boolean no_modifiers = !event.isAltPressed() && !event.isCtrlPressed() && !event.isMetaPressed(); if (pressed && unicode != 0 && no_modifiers) { mPressedTextKeys.add(keyCode); int[] codePoints = {unicode}; JniInterface.sendTextEvent(new String(codePoints, 0, 1)); return true; } if (!pressed && mPressedTextKeys.contains(keyCode)) { mPressedTextKeys.remove(keyCode); return true; } switch (keyCode) { // KEYCODE_AT, KEYCODE_POUND, KEYCODE_STAR and KEYCODE_PLUS are // deprecated, but they still need to be here for older devices and // third-party keyboards that may still generate these events. See // https://source.android.com/devices/input/keyboard-devices.html#legacy-unsupported-keys case KeyEvent.KEYCODE_AT: JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed); JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_2, pressed); return true; case KeyEvent.KEYCODE_POUND: JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed); JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_3, pressed); return true; case KeyEvent.KEYCODE_STAR: JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed); JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_8, pressed); return true; case KeyEvent.KEYCODE_PLUS: JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed); JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_EQUALS, pressed); return true; default: // We try to send all other key codes to the host directly. return JniInterface.sendKeyEvent(0, keyCode, pressed); } }
/** Called when the activity is finally finished. */ @Override public void onDestroy() { super.onDestroy(); JniInterface.disconnectFromHost(); }