package de.tudarmstadt.informatik.hostage.ui;
import java.util.ArrayList;
import java.util.HashMap;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.net.ConnectivityManager;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v4.content.LocalBroadcastManager;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
import android.widget.ViewAnimator;
import de.tudarmstadt.informatik.hostage.HoneyService;
import de.tudarmstadt.informatik.hostage.HoneyService.LocalBinder;
import de.tudarmstadt.informatik.hostage.R;
import de.tudarmstadt.informatik.hostage.commons.HelperUtils;
import de.tudarmstadt.informatik.hostage.logging.Logger;
import de.tudarmstadt.informatik.hostage.logging.SQLLogger;
/**
* MainActivity is the central activity for the GUI of the application.
* MainActivity is launched when the application is first started.
* It shows the user:
* - information about the network
* - light indicators for recorded attacks on each protocol
* - amount of attacks on each protocols
* The user can start and stop services.
* @author Mihai Plasoianu
* @author Lars Pandikow
*
*/
public class MainActivity extends Activity {
// String constants for whole application
/**
* Used for Broadcast between service and GUI. String: "de.tudarmstadt.informatik.hostage.BROADCAST"
*/
public static final String BROADCAST = "de.tudarmstadt.informatik.hostage.BROADCAST";
/**
* Used to store session related data in a SharedPrefereces. String: "de.tudarmstadt.informatik.hostage.SESSION_DATA"
*/
public static final String SESSION_DATA = "de.tudarmstadt.informatik.hostage.SESSION_DATA";
public static final String LISTENER = "_LISTENER";
public static final String HANDLER_COUNT = "_HANDLER_COUNT";
public static final String SSID = "SSID";
public static final String BSSID = "BSSID";
public static final String INTERNAL_IP = "INTERNAL_IP";
public static final String EXTERNAL_IP = "EXTERNAL_IP";
/**
* Integer representing a grey light.
*/
public static final int LIGHT_GREY = 0x01;
/**
* Integer representing a green light.
*/
public static final int LIGHT_GREEN = 0x02;
/**
* Integer representing a red light.
*/
public static final int LIGHT_RED = 0x03;
/**
* Integer representing a yellow light.
*/
public static final int LIGHT_YELLOW = 0x04;
private HoneyService mService;
private boolean serviceBound;
private SharedPreferences pref;
private Editor editor;
private Logger logger;
// variables for the swipe animation
private ViewAnimator viewAnimator;
private GestureDetector gestureDetector;
private Animation animFlipInLR;
private Animation animFlipOutLR;
private Animation animFlipInRL;
private Animation animFlipOutRL;
private ListView listView;
private ListViewAdapter adapter;
private String protocolClicked;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Create dynamic view elements
initViewAnimator();
initListView();
// Initialize Class variables
pref = getSharedPreferences(MainActivity.SESSION_DATA, Context.MODE_PRIVATE);
logger = new SQLLogger(this);
editor = pref.edit();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.action_settings:
startActivity(new Intent(this, SettingsActivity.class));
break;
case R.id.action_about:
startActivity(new Intent(this, AboutActivity.class));
break;
default:
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onStart() {
super.onStart();
//Register Broadcast Receiver
registerReceiver();
registerNetReceiver();
// Bind service if running, else check for connection change and delete sessionData
if (isServiceRunning()) {
bindService(getServiceIntent(), mConnection, BIND_AUTO_CREATE);
} else {
String bssid_old = pref.getString(MainActivity.BSSID, "");
String bssid_new = HelperUtils.getBSSID(this);
if(bssid_new == null || !bssid_new.equals(bssid_old)){
deleteSessionData();
}
}
// Update UI
updateUI();
updateConnectionInfo();
}
@Override
protected void onStop() {
//Unbind running service
if (isServiceRunning()) {
unbindService(mConnection);
}
// Unregister Broadcast Receiver
unregisterNetReceiver();
unregisterReceiver();
super.onStop();
}
@Override
protected void onDestroy(){
super.onDestroy();
// If service not running delete session data
if(!isServiceRunning()){
deleteSessionData();
}
}
/**
* Called when User presses on/off button
* @param view
*/
public void buttonOnOffClick(View view) {
if (((ToggleButton) view).isChecked()) {
if (isParanoid()) {
protocolClicked = "PANIC";
} else {
protocolClicked = "SMB";
}
startAndBind();
} else {
mService.stopListeners();
stopAndUnbind();
}
}
/**
* Starts the ViewLog activity, when the Button is pressed
* @see ViewLog
* @param view View elements which triggers the method call.
*/
public void showLog(View view){
startActivity(new Intent(this, ViewLog.class));
}
/**
* If mobile phone is connected to a wireless network starts the background service ands binds itself to it.
* Else notifies the user that service could not be started.
*/
private void startAndBind() {
if(HelperUtils.getBSSID(this) != null){
startService(getServiceIntent());
bindService();
} else{
ToggleButton button = (ToggleButton) findViewById(R.id.toggleButtonOnOff);
button.setChecked(false);
Toast.makeText(getApplicationContext(), "To start a service, first connect to a wireless network.", Toast.LENGTH_SHORT).show();
}
}
/**
* Binds service to Activity
* @see HoneyService
*/
private void bindService(){
bindService(getServiceIntent(), mConnection, BIND_AUTO_CREATE);
serviceBound = true;
}
/**
* Stops service and unbinds it.
* @see HoneyService
*/
private void stopAndUnbind() {
unbindService();
stopService(getServiceIntent());
}
/**
* Unbinds service.
* @see HoneyService
*/
private void unbindService(){
unbindService(mConnection);
serviceBound = false;
}
/**
* Connection to bind the background service
* @see HoneyService
*/
private ServiceConnection mConnection = new ServiceConnection() {
/**
* After the service is bound, check which has been clicked and start it.
* @see android.content.ServiceConnection#onServiceConnected(android.content.ComponentName)
*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = ((LocalBinder) service).getService();
if(protocolClicked != null && protocolClicked.equals("PANIC")){
mService.startListeners();
}else if (protocolClicked != null){
mService.toggleListener(protocolClicked);
}
protocolClicked = null;
}
/**
* After the service is unbound, delete reference.
* @see android.content.ServiceConnection#onServiceDisconnected(android.content.ComponentName)
*/
@Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
}
};
/**
* Returns an intent to start HoneyService.
* @return An Intent to start HoneyService
*/
private Intent getServiceIntent() {
return new Intent(this, HoneyService.class);
}
/**
* Checks if user selected paranoid mode.
* @return True when paranoid mode is selected, else returns false.
*/
private boolean isParanoid() {
return ((CheckBox) findViewById(R.id.checkBoxParanoid)).isChecked();
}
/**
* Initializes the ListView. Creating its contents dynamic from protocol protocols.xml
* @see /res/values/protocols.xml
*/
private void initListView() {
ArrayList> data = new ArrayList>();
for (String protocol : getResources().getStringArray(R.array.protocols)) {
HashMap d = new HashMap();
d.put("light", String.valueOf(R.drawable.light_grey));
d.put("protocol", protocol);
d.put("connections", "-");
data.add(d);
}
listView = (ListView) findViewById(R.id.listViewProtocols);
adapter = new ListViewAdapter(getLayoutInflater(), data);
listView.setAdapter(adapter);
listView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
});
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView> parent, View view,
int position, long id) {
String protocolName = (String) ((HashMap, ?>) adapter
.getItem(position)).get("protocol");
if (isServiceRunning()) {
mService.toggleListener(protocolName);
if(!mService.hasRunningListeners()){
stopAndUnbind();
}
}else{
protocolClicked = protocolName;
startAndBind();
}
}
});
}
/**
* Checks if a HoneService instance is running.
* @return True if HonerService is running, else false.
* @see HonerService
*/
private boolean isServiceRunning() {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (service.service.getClassName().equals(HoneyService.class.getName())) {
return true;
}
}
return false;
}
/**
* Deletes all session related Data.
*/
private void deleteSessionData(){
editor.clear();
editor.commit();
}
/**
* Register broadcast receiver for custom broadcast.
* @see MainActivity#BROADCAST
*/
private void registerReceiver() {
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver,
new IntentFilter(BROADCAST));
}
/**
* Unregisters broadcast receiver for custom broadcast.
* @see MainActivity#BROADCAST
*/
private void unregisterReceiver() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
}
/**
* Receiver for custom broadcast.
* @see MainActivity#BROADCAST
*/
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// Update user interface.
updateUI();
}
};
/**
* Register broadcast receiver for network state changes.
* @see ConnectivityManager#CONNECTIVITY_ACTION
*/
private void registerNetReceiver() {
IntentFilter intent = new IntentFilter();
intent.addAction(ConnectivityManager.CONNECTIVITY_ACTION); //"android.net.conn.CONNECTIVITY_CHANGE"
registerReceiver(netReceiver, intent);
}
/**
* Unregister broadcast receiver for network state changes.
*/
private void unregisterNetReceiver() {
unregisterReceiver(netReceiver);
}
/**
* Receiver for network state change events.
*/
private BroadcastReceiver netReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String bssid_old = pref.getString(BSSID, "");
String bssid_new = HelperUtils.getBSSID(context);
if ((bssid_new == null || !bssid_new.equals(bssid_old)) && serviceBound) {
Toast.makeText(getApplicationContext(),"Connection changed! Services stopped!", Toast.LENGTH_LONG).show();
unbindService();
}
updateConnectionInfo();
}
};
/**
* Updates Information shown by the GUI.
*/
private void updateUI() {
boolean activeListeners = false;
boolean activeHandlers = false;
boolean yellowLight = false;
//Check for all protocols if listeners are active and attacks have been recorded
//Update protocol lights and connection information.
for(String protocol : getResources().getStringArray(R.array.protocols)){
//Check if protocol is active
if(pref.getBoolean(protocol + LISTENER, false)){
activeListeners = true;
int handlerCount = pref.getInt(protocol + HANDLER_COUNT, 0);
//Check if attacks have been recorded in this session.
if(handlerCount > 0){
activeHandlers = true;
updateProtocolLight(LIGHT_RED, protocol);
updateProtocolConnections(handlerCount, protocol);
} else{
//Check if the bssid of the wireless network has already been recorded as infected.
if(logger.bssidSeen(protocol, HelperUtils.getBSSID(getApplicationContext()))){
updateProtocolLight(LIGHT_YELLOW, protocol);
yellowLight = true;
} else{
updateProtocolLight(LIGHT_GREEN, protocol);
}
updateProtocolConnections(0, protocol);
}
}else{
updateProtocolLight(LIGHT_GREY, protocol);
}
}
//Update the big attack indicator.
if (activeListeners) {
if (activeHandlers) {
updateStatusLight(LIGHT_RED);
} else {
if(yellowLight){
updateStatusLight(LIGHT_YELLOW);
} else {
updateStatusLight(LIGHT_GREEN);
}
}
((ToggleButton) findViewById(R.id.toggleButtonOnOff))
.setChecked(true);
findViewById(R.id.checkBoxParanoid).setEnabled(false);
} else {
updateStatusLight(LIGHT_GREY);
((ToggleButton) findViewById(R.id.toggleButtonOnOff))
.setChecked(false);
findViewById(R.id.checkBoxParanoid).setEnabled(true);
}
}
/**
* Sets the big light indicator.
* @param light Integer code to set the light color.
* @see MainActivity#LIGHT_GREY
* @see MainActivity#LIGHT_GREEN
* @see MainActivity#LIGHT_RED
* @see MainActivity#LIGHT_YELLOW
*/
private void updateStatusLight(int light) {
switch (light) {
case LIGHT_GREY:
((ImageView) findViewById(R.id.imageViewLight))
.setImageResource(R.drawable.light_grey_large);
break;
case LIGHT_GREEN:
((ImageView) findViewById(R.id.imageViewLight))
.setImageResource(R.drawable.light_green_large);
break;
case LIGHT_RED:
((ImageView) findViewById(R.id.imageViewLight))
.setImageResource(R.drawable.light_red_large);
break;
case LIGHT_YELLOW:
((ImageView) findViewById(R.id.imageViewLight))
.setImageResource(R.drawable.light_yellow_large);
break;
}
}
/**
* Sets the light indicator for a given protocol.
* @param light Integer code to set the light color.
* @param protocolName Name of the protocol which should be updated.
*/
private void updateProtocolLight(int light, String protocolName) {
for (int i = 0; i < adapter.getCount(); ++i) {
HashMap d = (HashMap) adapter
.getItem(i);
if (d.get("protocol").equals(protocolName)) {
switch (light) {
case LIGHT_GREY:
d.put("light", String.valueOf(R.drawable.light_grey));
d.put("connections", "-");
break;
case LIGHT_GREEN:
d.put("light", String.valueOf(R.drawable.light_green));
break;
case LIGHT_RED:
d.put("light", String.valueOf(R.drawable.light_red));
break;
case LIGHT_YELLOW:
d.put("light", String.valueOf(R.drawable.light_yellow));
break;
}
}
}
adapter.notifyDataSetChanged();
}
/**
* Sets the connections count for a given protocol
* @param connections New value for recorded connections.
* @param protocolName Name of the protocol which should be updated.
*/
private void updateProtocolConnections(int connections, String protocolName) {
for (int i = 0; i < adapter.getCount(); ++i) {
HashMap d = ((HashMap) adapter
.getItem(i));
if (d.get("protocol").equals(protocolName)) {
d.put("connections", String.valueOf(connections));
}
}
adapter.notifyDataSetChanged();
}
/**
* Gets Information about connection state and updates the GUI.
*/
private void updateConnectionInfo() {
//Get text fields
TextView ssidView = (TextView) findViewById(R.id.textViewSSIDValue);
TextView bssidView = (TextView) findViewById(R.id.textViewBSSIDValue);
TextView internalIPView = (TextView) findViewById(R.id.textViewInternalIPValue);
TextView externalIPView = (TextView) findViewById(R.id.textViewExternalIPValue);
//Update the connection information
HelperUtils.updateConnectionInfo(this);
//Get connection information
String ssid = pref.getString(SSID, "-");
String bssid = pref.getString(BSSID, "-");
String internalIP = pref.getString(INTERNAL_IP, "-");
String externalIP = pref.getString(EXTERNAL_IP, "-");
//Set text fields
if (ssid != null)
ssidView.setText(ssid);
else
ssidView.setText("-");
if (bssid != null)
bssidView.setText(bssid);
else
bssidView.setText("-");
if (internalIP != null)
internalIPView.setText(internalIP);
else
internalIPView.setText("-");
if (externalIP != null)
externalIPView.setText(externalIP);
else
externalIPView.setText("-");
}
/*############# Help functions for animation ##################*/
@Override
public boolean onTouchEvent(MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
/**
* Initializes variables for screen animation
*/
private void initViewAnimator() {
viewAnimator = (ViewAnimator) findViewById(R.id.viewAnimator);
gestureDetector = new GestureDetector(this, simpleOnGestureListener);
animFlipInLR = AnimationUtils.loadAnimation(this,
R.anim.in_left_to_right);
animFlipOutLR = AnimationUtils.loadAnimation(this,
R.anim.out_left_to_right);
animFlipInRL = AnimationUtils.loadAnimation(this,
R.anim.in_right_to_left);
animFlipOutRL = AnimationUtils.loadAnimation(this,
R.anim.out_right_to_left);
}
/**
* Called when a swipe to the Left is registered.
*/
private void swipeRightToLeft() {
if (viewAnimator.getDisplayedChild() == 0) {
viewAnimator.setInAnimation(animFlipInRL);
viewAnimator.setOutAnimation(animFlipOutRL);
viewAnimator.setDisplayedChild(1);
}
}
/**
* Called when a swipe to the Right is registered.
*/
private void swipeLeftToRight() {
if (viewAnimator.getDisplayedChild() == 1) {
viewAnimator.setInAnimation(animFlipInLR);
viewAnimator.setOutAnimation(animFlipOutLR);
viewAnimator.setDisplayedChild(0);
}
}
SimpleOnGestureListener simpleOnGestureListener = new SimpleOnGestureListener() {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
float sensitvity = 50;
if ((e1.getX() - e2.getX()) > sensitvity) {
swipeRightToLeft();
} else if ((e2.getX() - e1.getX()) > sensitvity) {
swipeLeftToRight();
}
return true;
}
};
}