/*
* Copyright (C) 2009-2010 Aubort Jean-Baptiste (Rorist)
* Licensed under GNU's GPL 2, see README
*/
package info.lamatricexiste.network;
import info.lamatricexiste.network.Network.HardwareAddress;
import info.lamatricexiste.network.Network.HostBean;
import info.lamatricexiste.network.Network.NetInfo;
import info.lamatricexiste.network.Utils.Export;
import info.lamatricexiste.network.Utils.Help;
import info.lamatricexiste.network.Utils.Prefs;
import info.lamatricexiste.network.Utils.Save;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnClickListener;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;
final public class ActivityDiscovery extends ActivityNet implements OnItemClickListener {
private final String TAG = "ActivityDiscovery";
public final static long VIBRATE = (long) 250;
public final static int SCAN_PORT_RESULT = 1;
public static final int MENU_SCAN_SINGLE = 0;
public static final int MENU_OPTIONS = 1;
public static final int MENU_HELP = 2;
private static final int MENU_EXPORT = 3;
private static LayoutInflater mInflater;
private int currentNetwork = 0;
private long network_ip = 0;
private long network_start = 0;
private long network_end = 0;
private List<HostBean> hosts = null;
private HostsAdapter adapter;
private Button btn_discover;
private AbstractDiscovery mDiscoveryTask = null;
// private SlidingDrawer mDrawer;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_PROGRESS);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.discovery);
mInflater = LayoutInflater.from(ctxt);
// Discover
btn_discover = (Button) findViewById(R.id.btn_discover);
btn_discover.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
startDiscovering();
}
});
// Options
Button btn_options = (Button) findViewById(R.id.btn_options);
btn_options.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
startActivity(new Intent(ctxt, Prefs.class));
}
});
// Hosts list
adapter = new HostsAdapter(ctxt);
ListView list = (ListView) findViewById(R.id.output);
list.setAdapter(adapter);
list.setItemsCanFocus(false);
list.setOnItemClickListener(this);
list.setEmptyView(findViewById(R.id.list_empty));
// Drawer
/*
* final View info = findViewById(R.id.info_container); mDrawer =
* (SlidingDrawer) findViewById(R.id.drawer);
* mDrawer.setOnDrawerScrollListener(new
* SlidingDrawer.OnDrawerScrollListener() { public void
* onScrollStarted() {
* info.setBackgroundResource(R.drawable.drawer_bg2); }
*
* public void onScrollEnded() { } });
* mDrawer.setOnDrawerCloseListener(new
* SlidingDrawer.OnDrawerCloseListener() { public void onDrawerClosed()
* { info.setBackgroundResource(R.drawable.drawer_bg); } }); EditText
* cidr_value = (EditText) findViewById(R.id.cidr_value); ((Button)
* findViewById(R.id.btn_cidr_plus)).setOnClickListener(new
* View.OnClickListener() { public void onClick(View v) { } });
* ((Button) findViewById(R.id.btn_cidr_minus)).setOnClickListener(new
* View.OnClickListener() { public void onClick(View v) { } });
*/
}
@Override
public void onResume() {
super.onResume();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, ActivityDiscovery.MENU_SCAN_SINGLE, 0, R.string.scan_single_title).setIcon(
android.R.drawable.ic_menu_mylocation);
menu.add(0, ActivityDiscovery.MENU_EXPORT, 0, R.string.preferences_export).setIcon(
android.R.drawable.ic_menu_save);
menu.add(0, ActivityDiscovery.MENU_OPTIONS, 0, R.string.btn_options).setIcon(
android.R.drawable.ic_menu_preferences);
menu.add(0, ActivityDiscovery.MENU_HELP, 0, R.string.preferences_help).setIcon(
android.R.drawable.ic_menu_help);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case ActivityDiscovery.MENU_SCAN_SINGLE:
scanSingle(this, null);
return true;
case ActivityDiscovery.MENU_OPTIONS:
startActivity(new Intent(ctxt, Prefs.class));
return true;
case ActivityDiscovery.MENU_HELP:
startActivity(new Intent(ctxt, Help.class));
return true;
case ActivityDiscovery.MENU_EXPORT:
export();
return true;
}
return false;
}
protected void setInfo() {
// Info
((TextView) findViewById(R.id.info_ip)).setText(info_ip_str);
((TextView) findViewById(R.id.info_in)).setText(info_in_str);
((TextView) findViewById(R.id.info_mo)).setText(info_mo_str);
// Scan button state
if (mDiscoveryTask != null) {
setButton(btn_discover, R.drawable.cancel, false);
btn_discover.setText(R.string.btn_discover_cancel);
btn_discover.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
cancelTasks();
}
});
}
if (currentNetwork != net.hashCode()) {
Log.i(TAG, "Network info has changed");
currentNetwork = net.hashCode();
// Cancel running tasks
cancelTasks();
} else {
return;
}
// Get ip information
network_ip = NetInfo.getUnsignedLongFromIp(net.ip);
if (prefs.getBoolean(Prefs.KEY_IP_CUSTOM, Prefs.DEFAULT_IP_CUSTOM)) {
// Custom IP
network_start = NetInfo.getUnsignedLongFromIp(prefs.getString(Prefs.KEY_IP_START,
Prefs.DEFAULT_IP_START));
network_end = NetInfo.getUnsignedLongFromIp(prefs.getString(Prefs.KEY_IP_END,
Prefs.DEFAULT_IP_END));
} else {
// Custom CIDR
if (prefs.getBoolean(Prefs.KEY_CIDR_CUSTOM, Prefs.DEFAULT_CIDR_CUSTOM)) {
net.cidr = Integer.parseInt(prefs.getString(Prefs.KEY_CIDR, Prefs.DEFAULT_CIDR));
}
// Detected IP
int shift = (32 - net.cidr);
if (net.cidr < 31) {
network_start = (network_ip >> shift << shift) + 1;
network_end = (network_start | ((1 << shift) - 1)) - 1;
} else {
network_start = (network_ip >> shift << shift);
network_end = (network_start | ((1 << shift) - 1));
}
// Reset ip start-end (is it really convenient ?)
Editor edit = prefs.edit();
edit.putString(Prefs.KEY_IP_START, NetInfo.getIpFromLongUnsigned(network_start));
edit.putString(Prefs.KEY_IP_END, NetInfo.getIpFromLongUnsigned(network_end));
edit.commit();
}
}
protected void setButtons(boolean disable) {
if (disable) {
setButtonOff(btn_discover, R.drawable.disabled);
} else {
setButtonOn(btn_discover, R.drawable.discover);
}
}
protected void cancelTasks() {
if (mDiscoveryTask != null) {
mDiscoveryTask.cancel(true);
mDiscoveryTask = null;
}
}
// Listen for Activity results
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case SCAN_PORT_RESULT:
if (resultCode == RESULT_OK) {
// Get scanned ports
if (data != null && data.hasExtra(HostBean.EXTRA)) {
HostBean host = data.getParcelableExtra(HostBean.EXTRA);
if (host != null) {
hosts.set(host.position, host);
}
}
}
default:
break;
}
}
public void onItemClick(AdapterView<?> parent, View view, final int position, long id) {
final HostBean host = hosts.get(position);
AlertDialog.Builder dialog = new AlertDialog.Builder(ActivityDiscovery.this);
dialog.setTitle(R.string.discover_action_title);
dialog.setItems(new CharSequence[] { getString(R.string.discover_action_scan),
getString(R.string.discover_action_rename) }, new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case 0:
// Start portscan
Intent intent = new Intent(ctxt, ActivityPortscan.class);
intent.putExtra(EXTRA_WIFI, NetInfo.isConnected(ctxt));
intent.putExtra(HostBean.EXTRA, host);
startActivityForResult(intent, SCAN_PORT_RESULT);
break;
case 1:
// Change name
// FIXME: TODO
final View v = mInflater.inflate(R.layout.dialog_edittext, null);
final EditText txt = (EditText) v.findViewById(R.id.edittext);
final Save s = new Save();
txt.setText(s.getCustomName(host));
final AlertDialog.Builder rename = new AlertDialog.Builder(
ActivityDiscovery.this);
rename.setView(v);
rename.setTitle(R.string.discover_action_rename);
rename.setPositiveButton(R.string.btn_ok, new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
final String name = txt.getText().toString();
host.hostname = name;
s.setCustomName(name, host.hardwareAddress);
adapter.notifyDataSetChanged();
Toast.makeText(ActivityDiscovery.this,
R.string.discover_action_saved, Toast.LENGTH_SHORT).show();
}
});
rename.setNegativeButton(R.string.btn_remove, new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
host.hostname = null;
s.removeCustomName(host.hardwareAddress);
adapter.notifyDataSetChanged();
Toast.makeText(ActivityDiscovery.this,
R.string.discover_action_deleted, Toast.LENGTH_SHORT)
.show();
}
});
rename.show();
break;
}
}
});
dialog.setNegativeButton(R.string.btn_discover_cancel, null);
dialog.show();
}
static class ViewHolder {
TextView host;
TextView mac;
TextView vendor;
ImageView logo;
}
// Custom ArrayAdapter
private class HostsAdapter extends ArrayAdapter<Void> {
public HostsAdapter(Context ctxt) {
super(ctxt, R.layout.list_host, R.id.list);
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_host, null);
holder = new ViewHolder();
holder.host = (TextView) convertView.findViewById(R.id.list);
holder.mac = (TextView) convertView.findViewById(R.id.mac);
holder.vendor = (TextView) convertView.findViewById(R.id.vendor);
holder.logo = (ImageView) convertView.findViewById(R.id.logo);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
final HostBean host = hosts.get(position);
if (host.deviceType == HostBean.TYPE_GATEWAY) {
holder.logo.setImageResource(R.drawable.router);
} else if (host.isAlive == 1 || !host.hardwareAddress.equals(NetInfo.NOMAC)) {
holder.logo.setImageResource(R.drawable.computer);
} else {
holder.logo.setImageResource(R.drawable.computer_down);
}
if (host.hostname != null && !host.hostname.equals(host.ipAddress)) {
holder.host.setText(host.hostname + " (" + host.ipAddress + ")");
} else {
holder.host.setText(host.ipAddress);
}
if (!host.hardwareAddress.equals(NetInfo.NOMAC)) {
holder.mac.setText(host.hardwareAddress);
if(host.nicVendor != null){
holder.vendor.setText(host.nicVendor);
} else {
holder.vendor.setText(R.string.info_unknown);
}
holder.mac.setVisibility(View.VISIBLE);
holder.vendor.setVisibility(View.VISIBLE);
} else {
holder.mac.setVisibility(View.GONE);
holder.vendor.setVisibility(View.GONE);
}
return convertView;
}
}
/**
* Discover hosts
*/
private void startDiscovering() {
int method = 0;
try {
method = Integer.parseInt(prefs.getString(Prefs.KEY_METHOD_DISCOVER,
Prefs.DEFAULT_METHOD_DISCOVER));
} catch (NumberFormatException e) {
Log.e(TAG, e.getMessage());
}
switch (method) {
case 1:
mDiscoveryTask = new DnsDiscovery(ActivityDiscovery.this);
break;
case 2:
// Root
break;
case 0:
default:
mDiscoveryTask = new DefaultDiscovery(ActivityDiscovery.this);
}
mDiscoveryTask.setNetwork(network_ip, network_start, network_end);
mDiscoveryTask.execute();
btn_discover.setText(R.string.btn_discover_cancel);
setButton(btn_discover, R.drawable.cancel, false);
btn_discover.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
cancelTasks();
}
});
makeToast(R.string.discover_start);
setProgressBarVisibility(true);
setProgressBarIndeterminateVisibility(true);
initList();
}
public void stopDiscovering() {
Log.e(TAG, "stopDiscovering()");
mDiscoveryTask = null;
setButtonOn(btn_discover, R.drawable.discover);
btn_discover.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
startDiscovering();
}
});
setProgressBarVisibility(false);
setProgressBarIndeterminateVisibility(false);
btn_discover.setText(R.string.btn_discover);
}
private void initList() {
// setSelectedHosts(false);
adapter.clear();
hosts = new ArrayList<HostBean>();
}
public void addHost(HostBean host) {
host.position = hosts.size();
hosts.add(host);
adapter.add(null);
}
public static void scanSingle(final Context ctxt, String ip) {
// Alert dialog
View v = LayoutInflater.from(ctxt).inflate(R.layout.scan_single, null);
final EditText txt = (EditText) v.findViewById(R.id.ip);
if (ip != null) {
txt.setText(ip);
}
AlertDialog.Builder dialogIp = new AlertDialog.Builder(ctxt);
dialogIp.setTitle(R.string.scan_single_title);
dialogIp.setView(v);
dialogIp.setPositiveButton(R.string.btn_scan, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dlg, int sumthin) {
// start scanportactivity
Intent intent = new Intent(ctxt, ActivityPortscan.class);
intent.putExtra(HostBean.EXTRA_HOST, txt.getText().toString());
try {
intent.putExtra(HostBean.EXTRA_HOSTNAME, (InetAddress.getByName(txt.getText()
.toString()).getHostName()));
} catch (UnknownHostException e) {
intent.putExtra(HostBean.EXTRA_HOSTNAME, txt.getText().toString());
}
ctxt.startActivity(intent);
}
});
dialogIp.setNegativeButton(R.string.btn_discover_cancel, null);
dialogIp.show();
}
private void export() {
final Export e = new Export(ctxt, hosts);
final String file = e.getFileName();
View v = mInflater.inflate(R.layout.dialog_edittext, null);
final EditText txt = (EditText) v.findViewById(R.id.edittext);
txt.setText(file);
AlertDialog.Builder getFileName = new AlertDialog.Builder(this);
getFileName.setTitle(R.string.export_choose);
getFileName.setView(v);
getFileName.setPositiveButton(R.string.export_save, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dlg, int sumthin) {
final String fileEdit = txt.getText().toString();
if (e.fileExists(fileEdit)) {
AlertDialog.Builder fileExists = new AlertDialog.Builder(ActivityDiscovery.this);
fileExists.setTitle(R.string.export_exists_title);
fileExists.setMessage(R.string.export_exists_msg);
fileExists.setPositiveButton(R.string.btn_yes,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
if (e.writeToSd(fileEdit)) {
makeToast(R.string.export_finished);
} else {
export();
}
}
});
fileExists.setNegativeButton(R.string.btn_no, null);
fileExists.show();
} else {
if (e.writeToSd(fileEdit)) {
makeToast(R.string.export_finished);
} else {
export();
}
}
}
});
getFileName.setNegativeButton(R.string.btn_discover_cancel, null);
getFileName.show();
}
// private List<String> getSelectedHosts(){
// List<String> hosts_s = new ArrayList<String>();
// int listCount = list.getChildCount();
// for(int i=0; i<listCount; i++){
// CheckBox cb = (CheckBox) list.getChildAt(i).findViewById(R.id.list);
// if(cb.isChecked()){
// hosts_s.add(hosts.get(i));
// }
// }
// return hosts_s;
// }
//
// private void setSelectedHosts(Boolean all){
// int listCount = list.getChildCount();
// for(int i=0; i<listCount; i++){
// CheckBox cb = (CheckBox) list.getChildAt(i).findViewById(R.id.list);
// if(all){
// cb.setChecked(true);
// } else {
// cb.setChecked(false);
// }
// }
// }
// private void makeToast(String msg) {
// Toast.makeText(getApplicationContext(), (CharSequence) msg,
// Toast.LENGTH_SHORT).show();
// }
public void makeToast(int msg) {
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
}
private void setButton(Button btn, int res, boolean disable) {
if (disable) {
setButtonOff(btn, res);
} else {
setButtonOn(btn, res);
}
}
private void setButtonOff(Button b, int drawable) {
b.setClickable(false);
b.setEnabled(false);
b.setCompoundDrawablesWithIntrinsicBounds(drawable, 0, 0, 0);
}
private void setButtonOn(Button b, int drawable) {
b.setClickable(true);
b.setEnabled(true);
b.setCompoundDrawablesWithIntrinsicBounds(drawable, 0, 0, 0);
}
}