Commit 5bceb653 authored by mar-v-in's avatar mar-v-in
Browse files

Java/Android stuff (me coding dirty \o/)

parent a89547da
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.hacksaar.andtuer">
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="17"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name="de.hacksaar.andtuer.DoorActivity" android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="de.hacksaar.andtuer.DoorSettings" android:label="Settings"/>
</application>
</manifest>
# This file is automatically generated by IntelliJ IDEA
# Project target.
target=android-7
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout android:layout_height="wrap_content" android:layout_width="wrap_content"
android:layout_centerInParent="true" android:orientation="vertical">
<Button android:layout_height="wrap_content" android:layout_width="wrap_content"
android:id="@+id/connect_button"
android:text="@string/connect"/>
<Button android:layout_height="wrap_content" android:layout_width="wrap_content" android:id="@+id/buzz_button"
android:text="@string/buzz" android:enabled="false"/>
<Button android:layout_height="wrap_content" android:layout_width="wrap_content" android:id="@+id/open_button"
android:text="@string/open_door" android:enabled="false"/>
<Button android:layout_height="wrap_content" android:layout_width="wrap_content" android:id="@+id/close_button"
android:text="@string/close_door" android:enabled="false"/>
<Button android:layout_height="wrap_content" android:layout_width="wrap_content"
android:id="@+id/disconnect_button" android:text="@string/disconnect" android:enabled="false"/>
</LinearLayout>
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/menu_settings" android:icon="@android:drawable/ic_menu_preferences"
android:title="@string/preferences" android:showAsAction="always"/>
</menu>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Hacksaar AndTuer</string>
<string name="connect">Connect</string>
<string name="disconnect">Disconnect</string>
<string name="buzz">Buzz</string>
<string name="open_door">Open door</string>
<string name="close_door">Close door</string>
<string name="preferences">Preferences</string>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory android:title="Server">
<EditTextPreference android:key="pref_server_hostname" android:title="Hostname"
android:defaultValue="192.168.178.222"/>
<de.hacksaar.andtuer.IntegerTextPreference android:key="pref_server_port" android:title="Port"
android:inputType="number" android:defaultValue="22"/>
</PreferenceCategory>
<PreferenceCategory android:title="User">
<EditTextPreference android:key="pref_user_username" android:title="Username"/>
<EditTextPreference android:key="pref_user_keyfile" android:title="Keyfile"
android:defaultValue="/sdcard/.ssh/id_rsa"/>
</PreferenceCategory>
</PreferenceScreen>
\ No newline at end of file
package de.hacksaar.andtuer;
import android.util.Log;
import de.hacksaar.javatuer.TuerLogging;
public class AndroidLogging extends TuerLogging {
@Override
public void debug(String tag, String msg) {
Log.d(tag, msg);
}
@Override
public void exception(String tag, Throwable t) {
Log.w(tag, t);
}
@Override
public void info(String tag, String msg) {
Log.i(tag, msg);
}
}
package de.hacksaar.andtuer;
import android.os.AsyncTask;
import android.util.Log;
import de.hacksaar.javatuer.InteractiveLogin;
import de.hacksaar.javatuer.TyshellClient;
import java.util.LinkedList;
import java.util.Queue;
class AsyncTyshell extends AsyncTask<Void, Void, Void> {
private static final String TAG = "AsyncTyshell";
private final String hostname;
private final int port;
private final String username;
private final String keyFile;
private final Prompter prompter;
private final Queue<String> messages = new LinkedList<>();
private final Object promptWait = new Object();
private String promptResultString;
private boolean promptResultBoolean;
private boolean disconnect = true;
AsyncTyshell(String hostname, int port, String username, String keyFile, Prompter prompter) {
this.hostname = hostname;
this.port = port;
this.username = username;
this.keyFile = keyFile;
this.prompter = prompter;
}
private void awaitPrompt() {
synchronized (promptWait) {
try {
promptWait.wait();
} catch (InterruptedException e) {
Log.w(TAG, e);
}
}
}
public void disconnect() {
disconnect = false;
synchronized (promptWait) {
promptWait.notify();
}
synchronized (messages) {
messages.notify();
}
}
@Override
protected Void doInBackground(Void... voids) {
TyshellClient client = new TyshellClient(hostname, port, new AndroidLogging());
client.connect(username, keyFile, new AsyncInteractiveLogin());
while (disconnect) {
String msg = null;
synchronized (messages) {
while (disconnect && (msg = messages.poll()) == null) {
try {
messages.wait();
} catch (InterruptedException e) {
return null;
}
}
}
if (msg == null) {
break;
}
client.sendCommand(msg);
}
client.disconnect();
return null;
}
public void promptResult(boolean result) {
promptResultBoolean = result;
synchronized (promptWait) {
promptWait.notify();
}
}
public void promptResult(String result) {
promptResultString = result;
synchronized (promptWait) {
promptWait.notify();
}
}
public void sendCommand(String string) {
synchronized (messages) {
messages.add(string);
messages.notify();
}
}
public interface Prompter {
void promptBoolean(String message);
void promptString(String message);
void sendMessage(String message);
}
private class AsyncInteractiveLogin extends InteractiveLogin {
AsyncInteractiveLogin() {
}
@Override
public String promptKeyPassphrase(String question) {
prompter.promptString(question);
awaitPrompt();
return promptResultString;
}
@Override
public String promptUserPassword(String question) {
prompter.promptString(question);
awaitPrompt();
return promptResultString;
}
@Override
public boolean promptYesNo(String question) {
prompter.promptBoolean(question);
awaitPrompt();
return promptResultBoolean;
}
@Override
public void showMessage(String s) {
prompter.sendMessage(s);
}
}
}
package de.hacksaar.andtuer;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.InputType;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
public class DoorActivity extends Activity implements View.OnClickListener {
private static final String TAG = "DoorActivity";
private static final int DIALOG_BOOLEAN = 7;
private static final int DIALOG_STRING = 14;
private static final int TEXT_ID = 42;
private final AsyncTyshell.Prompter prompter = new DialogPrompter();
private AsyncTyshell task;
private String pendingMessage;
private Dialog askBooleanDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(null);
builder.setMessage(pendingMessage);
builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int whichButton) {
assert task != null;
task.promptResult(true);
}
});
builder.setNegativeButton("No", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
assert task != null;
task.promptResult(false);
}
});
return builder.create();
}
private Dialog askStringDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(null);
builder.setMessage(pendingMessage);
final EditText input = new EditText(this);
input.setId(TEXT_ID);
input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
builder.setView(input);
builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int whichButton) {
assert task != null;
String value = input.getText().toString();
task.promptResult(value);
}
});
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int whichButton) {
assert task != null;
task.promptResult(null);
}
});
return builder.create();
}
private void onBuzzClick() {
if (task != null) {
task.sendCommand("buzz");
}
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.connect_button:
onConnectClick();
break;
case R.id.buzz_button:
onBuzzClick();
break;
case R.id.open_button:
onOpenClick();
break;
case R.id.close_button:
onCloseClick();
break;
case R.id.disconnect_button:
onDisconnectClick();
break;
}
}
private void onCloseClick() {
if (task != null) {
task.sendCommand("close");
}
}
private void onConnectClick() {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
task = new AsyncTyshell(preferences.getString(DoorSettings.PREF_SERVER_HOSTNAME, DoorSettings.DEFAULT_HOST),
preferences.getInt(DoorSettings.PREF_SERVER_PORT, DoorSettings.DEFAULT_PORT),
preferences.getString(DoorSettings.PREF_USER_USERNAME, null),
preferences.getString(DoorSettings.PREF_USER_KEYFILE, DoorSettings.DEFAULT_KEYFILE),
prompter);
task.execute();
findViewById(R.id.open_button).setEnabled(true);
findViewById(R.id.close_button).setEnabled(true);
findViewById(R.id.buzz_button).setEnabled(true);
findViewById(R.id.disconnect_button).setEnabled(true);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.door);
findViewById(R.id.open_button).setOnClickListener(this);
findViewById(R.id.close_button).setOnClickListener(this);
findViewById(R.id.buzz_button).setOnClickListener(this);
findViewById(R.id.disconnect_button).setOnClickListener(this);
findViewById(R.id.connect_button).setOnClickListener(this);
}
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case DIALOG_BOOLEAN:
return askBooleanDialog();
case DIALOG_STRING:
return askStringDialog();
default:
return super.onCreateDialog(id);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return super.onCreateOptionsMenu(menu);
}
private void onDisconnectClick() {
if (task != null) {
task.sendCommand("exit");
task.disconnect();
}
findViewById(R.id.open_button).setEnabled(false);
findViewById(R.id.close_button).setEnabled(false);
findViewById(R.id.buzz_button).setEnabled(false);
findViewById(R.id.disconnect_button).setEnabled(false);
}
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_settings:
startActivity(new Intent(this, DoorSettings.class));
return true;
default:
return super.onMenuItemSelected(featureId, item);
}
}
private void onOpenClick() {
if (task != null) {
task.sendCommand("open");
}
}
@Override
protected void onPrepareDialog(int id, Dialog dialog) {
switch (id) {
case DIALOG_STRING:
((TextView) dialog.findViewById(TEXT_ID)).setText("");
case DIALOG_BOOLEAN:
((AlertDialog) dialog).setMessage(pendingMessage);
break;
default:
super.onPrepareDialog(id, dialog);
}
}
private class DialogPrompter implements AsyncTyshell.Prompter {
DialogPrompter() {
}
@Override
public void promptBoolean(String message) {
pendingMessage = message;
runOnUiThread(new Runnable() {
@Override
public void run() {
showDialog(DIALOG_BOOLEAN);
}
});
}
@Override
public void promptString(String message) {
pendingMessage = message;
runOnUiThread(new Runnable() {
@Override
public void run() {
showDialog(DIALOG_STRING);
}
});
}
@Override
public void sendMessage(final String message) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Log.d(TAG, "Message: " + message);
}
});
}
}
}
\ No newline at end of file
package de.hacksaar.andtuer;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Environment;
import android.preference.Preference;
import android.preference.PreferenceActivity;
public class DoorSettings extends PreferenceActivity implements Preference.OnPreferenceChangeListener {
public static final int DEFAULT_PORT = 22;
public static final String DEFAULT_HOST = "192.168.178.222";
public static final String DEFAULT_KEYFILE = Environment.getExternalStorageDirectory().getPath() + "/.ssh/id_rsa";
private static final String UNSET = "<unset>";
public static final String PREF_SERVER_PORT = "pref_server_port";
public static final String PREF_USER_USERNAME = "pref_user_username";
public static final String PREF_USER_KEYFILE = "pref_user_keyfile";
public static final String PREF_SERVER_HOSTNAME = "pref_server_hostname";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
Preference hostnamePreference = findPreference(PREF_SERVER_HOSTNAME);
hostnamePreference.setOnPreferenceChangeListener(this);
SharedPreferences sharedPreferences = getPreferenceManager().getSharedPreferences();
hostnamePreference.setSummary(sharedPreferences.getString(PREF_SERVER_HOSTNAME, DEFAULT_HOST));
Preference portPreference = findPreference(PREF_SERVER_PORT);
portPreference.setOnPreferenceChangeListener(this);
portPreference.setSummary(Integer.toString(sharedPreferences.getInt(PREF_SERVER_PORT, DEFAULT_PORT)));
Preference usernamePreference = findPreference(PREF_USER_USERNAME);
usernamePreference.setOnPreferenceChangeListener(this);
usernamePreference.setSummary(sharedPreferences.getString(PREF_USER_USERNAME, UNSET));
Preference keyfilePreference = findPreference(PREF_USER_KEYFILE);
keyfilePreference.setOnPreferenceChangeListener(this);
keyfilePreference.setSummary(sharedPreferences.getString(PREF_USER_KEYFILE, DEFAULT_KEYFILE));
}
@Override
public boolean onPreferenceChange(Preference preference, Object o) {
SharedPreferences sharedPreferences = getPreferenceManager().getSharedPreferences();
if (preference.getKey().equals(PREF_SERVER_PORT)) {
preference.setSummary(
Integer.toString(sharedPreferences.getInt(preference.getKey(), DEFAULT_PORT)));
} else {
preference.setSummary(sharedPreferences.getString(preference.getKey(), UNSET));
}
return true;
}
}
\ No newline at end of file
package de.hacksaar.andtuer;
import android.content.Context;
import android.preference.EditTextPreference;
import android.util.AttributeSet;
public class IntegerTextPreference extends EditTextPreference {
public IntegerTextPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public IntegerTextPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public IntegerTextPreference(Context context) {
super(context);
}
@Override
protected String getPersistedString(String defaultReturnValue) {
return String.valueOf(getPersistedInt(-1));
}
@Override
protected boolean persistString(String value) {
return persistInt(Integer.valueOf(value));
}
}
package de.hacksaar.javatuer;
public class DummyLogging extends TuerLogging {
@Override
public void debug(String tag, String msg) {
// do nothing
}
@Override
public void exception(String tag, Throwable t) {
// do nothing
}
@Override
public void info(String tag, String msg) {
// do nothing
}
}
package de.hacksaar.javatuer;
import com.jcraft.jsch.UserInfo;
public abstract class InteractiveLogin implements UserInfo {
private String password;
private String passphrase;
@Override
public String getPassphrase() {
return passphrase;
}