package net.i2p.android.router.activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.view.View; import android.widget.Button; import android.widget.TextView; import java.io.File; import java.text.DecimalFormat; import java.util.logging.Level; import java.util.logging.Logger; import net.i2p.android.router.R; import net.i2p.android.router.service.RouterService; import net.i2p.android.router.util.Util; import net.i2p.data.DataHelper; import net.i2p.router.RouterContext; public class MainActivity extends I2PActivityBase { private Handler _handler; private Runnable _updater; private Runnable _oneShotUpdate; private String _savedStatus; protected static final String PROP_NEW_INSTALL = "i2p.newInstall"; protected static final String PROP_NEW_VERSION = "i2p.newVersion"; protected static final int DIALOG_NEW_INSTALL = 0; protected static final int DIALOG_NEW_VERSION = 1; private boolean _keep = true; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Init stuff here so settings work. _myDir = getFilesDir().getAbsolutePath(); if (savedInstanceState != null) { String saved = savedInstanceState.getString("status"); if (saved != null) { _savedStatus = saved; } } RouterService svc = _routerService; if (!(svc != null && _isBound)) { Util.e("Initializing..."); InitActivities init = new InitActivities(this); init.debugStuff(); init.initialize(); } setContentView(R.layout.main); Button b = (Button) findViewById(R.id.news_button); b.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { Intent intent = new Intent(view.getContext(), NewsActivity.class); startActivity(intent); } }); b = (Button) findViewById(R.id.releasenotes_button); b.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { Intent intent = new Intent(view.getContext(), TextResourceActivity.class); intent.putExtra(TextResourceActivity.TEXT_RESOURCE_ID, R.raw.releasenotes_txt); startActivity(intent); } }); b = (Button) findViewById(R.id.licenses_button); b.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { Intent intent = new Intent(view.getContext(), LicenseActivity.class); //Intent intent = new Intent(view.getContext(), TextResourceActivity.class); //intent.putExtra(TextResourceActivity.TEXT_RESOURCE_ID, R.raw.licenses_txt); startActivity(intent); } }); b = (Button) findViewById(R.id.website_button); b.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { Intent intent = new Intent(view.getContext(), WebActivity.class); //intent.setData((new Uri.Builder()).scheme("http").authority("www.i2p2.de").path("/").build()); intent.setData(Uri.parse("http://www.i2p2.de/")); startActivity(intent); } }); b = (Button) findViewById(R.id.faq_button); b.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { Intent intent = new Intent(view.getContext(), WebActivity.class); //intent.setData((new Uri.Builder()).scheme("http").authority("www.i2p2.de").path("/faq").build()); intent.setData(Uri.parse("http://www.i2p2.de/faq")); startActivity(intent); } }); b = (Button) findViewById(R.id.welcome_button); b.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { Intent intent = new Intent(view.getContext(), WebActivity.class); intent.putExtra(WebActivity.HTML_RESOURCE_ID, R.raw.welcome_html); startActivity(intent); } }); b = (Button) findViewById(R.id.addressbook_button); b.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { Intent intent = new Intent(view.getContext(), AddressbookActivity.class); startActivity(intent); } }); b = (Button) findViewById(R.id.logs_button); b.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { Intent intent = new Intent(view.getContext(), LogActivity.class); startActivity(intent); } }); b = (Button) findViewById(R.id.error_button); b.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { Intent intent = new Intent(view.getContext(), LogActivity.class); intent.putExtra(LogActivity.ERRORS_ONLY, true); startActivity(intent); } }); b = (Button) findViewById(R.id.peers_button); b.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { Intent intent = new Intent(view.getContext(), PeersActivity.class); startActivity(intent); } }); b = (Button) findViewById(R.id.router_start_button); b.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { RouterService svc = _routerService; if (svc != null && _isBound) { setPref(PREF_AUTO_START, true); svc.manualStart(); } else { (new File(_myDir, "wrapper.log")).delete(); startRouter(); } updateOneShot(); } }); /* hidden, unused b = (Button) findViewById(R.id.router_stop_button); b.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { RouterService svc = _routerService; if (svc != null && _isBound) { setPref(PREF_AUTO_START, false); svc.manualStop(); updateOneShot(); } } }); */ b = (Button) findViewById(R.id.router_quit_button); b.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { RouterService svc = _routerService; if (svc != null && _isBound) { setPref(PREF_AUTO_START, false); svc.manualQuit(); updateOneShot(); } } }); _handler = new Handler(); _updater = new Updater(); _oneShotUpdate = new OneShotUpdate(); } @Override public void onStart() { super.onStart(); _handler.removeCallbacks(_updater); _handler.removeCallbacks(_oneShotUpdate); if (_savedStatus != null) { TextView tv = (TextView) findViewById(R.id.main_status_text); tv.setText(_savedStatus); } checkDialog(); _handler.postDelayed(_updater, 100); } @Override public void onStop() { RouterContext ctx = getRouterContext(); _keep = Util.isConnected(this) && ctx != null; super.onStop(); _handler.removeCallbacks(_updater); _handler.removeCallbacks(_oneShotUpdate); } @Override public void onResume() { super.onResume(); updateOneShot(); } @Override public void onSaveInstanceState(Bundle outState) { if (_savedStatus != null) outState.putString("status", _savedStatus); super.onSaveInstanceState(outState); } private void updateOneShot() { _handler.postDelayed(_oneShotUpdate, 100); } private class OneShotUpdate implements Runnable { public void run() { updateVisibility(); updateStatus(); } } private class Updater implements Runnable { private int counter; public void run() { updateVisibility(); if (counter++ % 3 == 0) updateStatus(); _handler.postDelayed(this, 2500); } } private void updateVisibility() { RouterService svc = _routerService; boolean showStart = ((svc == null) || (!_isBound) || svc.canManualStart()) && Util.isConnected(this); Button start = (Button) findViewById(R.id.router_start_button); start.setVisibility(showStart ? View.VISIBLE : View.INVISIBLE); boolean showStop = svc != null && _isBound && svc.canManualStop(); // Old stop but leave in memory. Always hide for now. // Button stop = (Button) findViewById(R.id.router_stop_button); // stop.setVisibility( /* showStop ? View.VISIBLE : */ View.INVISIBLE); Button quit = (Button) findViewById(R.id.router_quit_button); quit.setVisibility(showStop ? View.VISIBLE : View.INVISIBLE); } @Override public void onDestroy() { // RouterContext ctx = getRouterContext(); super.onDestroy(); if (!_keep) { Thread t = new Thread(new KillMe()); t.start(); } } private class KillMe implements Runnable { public void run() { try { Thread.sleep(500); // is 500ms long enough? } catch (InterruptedException ex) { } System.exit(0); } } private void updateStatus() { RouterContext ctx = getRouterContext(); TextView tv = (TextView) findViewById(R.id.main_status_text); if (!Util.isConnected(this)) { tv.setText("No Internet connection is available"); tv.setVisibility(View.VISIBLE); } else if (ctx != null) { short reach = ctx.commSystem().getReachabilityStatus(); int active = ctx.commSystem().countActivePeers(); int known = Math.max(ctx.netDb().getKnownRouters() - 1, 0); int inEx = ctx.tunnelManager().getFreeTunnelCount(); int outEx = ctx.tunnelManager().getOutboundTunnelCount(); int inCl = ctx.tunnelManager().getInboundClientTunnelCount(); int outCl = ctx.tunnelManager().getOutboundClientTunnelCount(); int part = ctx.tunnelManager().getParticipatingCount(); double dLag = ctx.statManager().getRate("jobQueue.jobLag").getRate(60000).getAverageValue(); String jobLag = DataHelper.formatDuration((long) dLag); String msgDelay = DataHelper.formatDuration(ctx.throttle().getMessageDelay()); String uptime = DataHelper.formatDuration(ctx.router().getUptime()); String netstatus = "Unknown"; if(reach == net.i2p.router.CommSystemFacade.STATUS_DIFFERENT) netstatus = "Different"; if(reach == net.i2p.router.CommSystemFacade.STATUS_HOSED) netstatus = "Hosed"; if(reach == net.i2p.router.CommSystemFacade.STATUS_OK) netstatus = "OK"; if(reach == net.i2p.router.CommSystemFacade.STATUS_REJECT_UNSOLICITED) netstatus = "Reject Unsolicited"; // String tunnelStatus = ctx.throttle().getTunnelStatus(); // ctx.commSystem().getReachabilityStatus(); double inBW = ctx.bandwidthLimiter().getReceiveBps() / 1024; double outBW = ctx.bandwidthLimiter().getSendBps() / 1024; // control total width DecimalFormat fmt; if (inBW >= 1000 || outBW >= 1000) fmt = new DecimalFormat("#0"); else if (inBW >= 100 || outBW >= 100) fmt = new DecimalFormat("#0.0"); else fmt = new DecimalFormat("#0.00"); double kBytesIn = ctx.bandwidthLimiter().getTotalAllocatedInboundBytes() / 1024; double kBytesOut = ctx.bandwidthLimiter().getTotalAllocatedOutboundBytes() / 1024; // control total width DecimalFormat kBfmt; if (kBytesIn >= 1000 || kBytesOut >= 1000) kBfmt = new DecimalFormat("#0"); else if (kBytesIn >= 100 || kBytesOut >= 100) kBfmt = new DecimalFormat("#0.0"); else kBfmt = new DecimalFormat("#0.00"); String status = "ROUTER STATUS" + "\nNetwork: "+ netstatus + "\nPeers active/known: " + active + " / " + known + "\nExploratory Tunnels in/out: " + inEx + " / " + outEx + "\nClient Tunnels in/out: " + inCl + " / " + outCl; // Need to see if we have the participation option set to on. // I thought there was a router setting for that? I guess not! WHY NOT? // For now, if zero, don't show anything. This is done to not alert the // end user into thinking that this router must participate. String participate = ""; if(part != 0) participate = "\nParticipating: " + part; String details = "\nBandwidth in/out: " + fmt.format(inBW) + " / " + fmt.format(outBW) + " KBps" + "\nData usage in/out: " + kBfmt.format(kBytesIn) + " / " + kBfmt.format(kBytesOut) + " KB" + "\nMemory: " + DataHelper.formatSize(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) + "B / " + DataHelper.formatSize(Runtime.getRuntime().maxMemory()) + 'B' + "\nJob Lag: " + jobLag + "\nMsg Delay: " + msgDelay + "\nUptime: " + uptime; _savedStatus = status + participate + details; tv.setText(_savedStatus); tv.setVisibility(View.VISIBLE); } else { // network but no router context tv.setVisibility(View.INVISIBLE); /**** RouterService svc = _routerService; String status = "connected? " + Util.isConnected(this) + "\nMemory: " + DataHelper.formatSize(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) + "B / " + DataHelper.formatSize(Runtime.getRuntime().maxMemory()) + 'B' + "\nhave ctx? " + (ctx != null) + "\nhave svc? " + (svc != null) + "\nis bound? " + _isBound + "\nsvc state: " + (svc == null ? "null" : svc.getState()) + "\ncan start? " + (svc == null ? "null" : svc.canManualStart()) + "\ncan stop? " + (svc == null ? "null" : svc.canManualStop()); tv.setText(status); tv.setVisibility(View.VISIBLE); ****/ } } private void checkDialog() { String oldVersion = getPref(PREF_INSTALLED_VERSION, "??"); if (oldVersion.equals("??")) { showDialog(DIALOG_NEW_INSTALL); } else { String currentVersion = Util.getOurVersion(this); if (!oldVersion.equals(currentVersion)) showDialog(DIALOG_NEW_VERSION); } } @Override protected Dialog onCreateDialog(int id) { final String currentVersion = Util.getOurVersion(this); Dialog rv = null; AlertDialog.Builder b = new AlertDialog.Builder(this); switch (id) { case DIALOG_NEW_INSTALL: b.setMessage(getResources().getText(R.string.welcome_new_install)) .setCancelable(false) .setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { setPref(PREF_INSTALLED_VERSION, currentVersion); dialog.cancel(); MainActivity.this.removeDialog(id); } }) .setNeutralButton("Release Notes", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { setPref(PREF_INSTALLED_VERSION, currentVersion); dialog.cancel(); MainActivity.this.removeDialog(id); Intent intent = new Intent(MainActivity.this, TextResourceActivity.class); intent.putExtra(TextResourceActivity.TEXT_RESOURCE_ID, R.raw.releasenotes_txt); startActivity(intent); } }) .setNegativeButton("Licenses", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { setPref(PREF_INSTALLED_VERSION, currentVersion); dialog.cancel(); MainActivity.this.removeDialog(id); Intent intent = new Intent(MainActivity.this, LicenseActivity.class); startActivity(intent); } }); rv = b.create(); break; case DIALOG_NEW_VERSION: b.setMessage(getResources().getText(R.string.welcome_new_version) + " " + currentVersion) .setCancelable(true) .setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { setPref(PREF_INSTALLED_VERSION, currentVersion); try { dialog.dismiss(); } catch (Exception e) {} MainActivity.this.removeDialog(id); } }) .setNegativeButton("Release Notes", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { setPref(PREF_INSTALLED_VERSION, currentVersion); try { dialog.dismiss(); } catch (Exception e) {} MainActivity.this.removeDialog(id); Intent intent = new Intent(MainActivity.this, TextResourceActivity.class); intent.putExtra(TextResourceActivity.TEXT_RESOURCE_ID, R.raw.releasenotes_txt); startActivity(intent); } }); rv = b.create(); break; } return rv; } }