package org.openintents.wifiserver;
import java.io.IOException;
import org.openintents.distribution.DistributionLibraryActivity;
import org.openintents.wifiserver.preference.OIWiFiPreferencesActivity_;
import org.openintents.wifiserver.preference.OiWiFiPreferences_;
import org.openintents.wifiserver.requesthandler.AvailableAppsHandler;
import org.openintents.wifiserver.requesthandler.FileHandler_;
import org.openintents.wifiserver.requesthandler.LoginHandler_;
import org.openintents.wifiserver.requesthandler.LogoutHandler;
import org.openintents.wifiserver.requesthandler.notes.DeleteNote;
import org.openintents.wifiserver.requesthandler.notes.GetNote;
import org.openintents.wifiserver.requesthandler.notes.NewNote;
import org.openintents.wifiserver.requesthandler.notes.UpdateNote;
import org.openintents.wifiserver.requesthandler.shoppinglist.DeleteItem;
import org.openintents.wifiserver.requesthandler.shoppinglist.DeleteShoppinglist;
import org.openintents.wifiserver.requesthandler.shoppinglist.GetItem;
import org.openintents.wifiserver.requesthandler.shoppinglist.GetShoppinglist;
import org.openintents.wifiserver.requesthandler.shoppinglist.NewShoppinglist;
import org.openintents.wifiserver.requesthandler.shoppinglist.RenameShoppinglist;
import org.openintents.wifiserver.requesthandler.shoppinglist.UpdateItem;
import org.openintents.wifiserver.webserver.ServerStatusListener;
import org.openintents.wifiserver.webserver.WebServer;
import org.openintents.wifiserver.webserver.WebServer.Status;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.util.Log;
import android.view.Menu;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
import com.googlecode.androidannotations.annotations.AfterViews;
import com.googlecode.androidannotations.annotations.Click;
import com.googlecode.androidannotations.annotations.EActivity;
import com.googlecode.androidannotations.annotations.OptionsItem;
import com.googlecode.androidannotations.annotations.OptionsMenu;
import com.googlecode.androidannotations.annotations.ViewById;
import com.googlecode.androidannotations.annotations.sharedpreferences.Pref;
/**
* This class represents the main activity. It must not be used directly by the
* manifest file, because it is sub-classed by AndroidAnnotations. Instead use
* <b>OIWifiServerActivity_</b> when referencing this class.
*
* @author Stanley Förster
*/
@SuppressLint("Registered")
@EActivity(R.layout.main)
@OptionsMenu(R.menu.menu)
public class OIWiFiServerActivity extends DistributionLibraryActivity {
private static final int MENU_DISTRIBUTION_START = Menu.FIRST + 100; // MUST BE LAST
private static final int DIALOG_DISTRIBUTION_START = 100; // MUST BE LAST
private final static String TAG = OIWiFiServerActivity.class.getSimpleName();
@ViewById protected TextView textWifiStatus;
@ViewById protected TextView textURL;
@ViewById protected ToggleButton toggleStartStopServer;
/**
* Represents shared preferences of the application. Use this field to
* access and modify preferences.
*/
@Pref protected OiWiFiPreferences_ prefs;
private ConnectivityReceiver mConnectivityReceiver = null;
private WebServer mWebServer = null;
////////////////////////////////////////////////////////////////////////////////
////////////////////////////// LIVECYCLE ///////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/**
* This method is called after AndroidAnnotations injected the views in the
* {@link #onCreate(android.os.Bundle)} method.<br />
* Use this one instead of the original {@link #onCreate(android.os.Bundle)}
* method to avoid exceptions because of uninitialized fields.
*/
@AfterViews
protected void onCreate() {
mDistribution.setFirst(MENU_DISTRIBUTION_START, DIALOG_DISTRIBUTION_START);
if (mDistribution.showEulaOrNewVersion())
return;
mConnectivityReceiver = new ConnectivityReceiver() {
@Override
public void onConnectionChanged(ConnectionType type) {
if (type != ConnectionType.NET_WIFI)
wifiDisconnected();
else
wifiConnected();
}
};
this.registerReceiver(mConnectivityReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
}
/**
* <p>
* {@inheritDoc}
* </p>
* If the server is running, it will be stopped and the connectivity
* receiver will be unregistered.
*/
@Override
protected void onDestroy() {
super.onDestroy();
stopServer();
if (mConnectivityReceiver != null)
this.unregisterReceiver(mConnectivityReceiver);
}
/**
* After the connectivity receiver received a connection changed event which
* indicated that the WiFi connection is lost, this method is called, which
* stops the server and disables the start server button.
*/
private void wifiDisconnected() {
textWifiStatus.setText(R.string.disconnected);
if (toggleStartStopServer.isChecked())
toggleStartStopServer.toggle();
toggleStartStopServer.setEnabled(false);
stopServer();
}
/**
* After a connection event which indicates that a WiFi connection has been
* established, this method is called and updates the GUI.
*/
private void wifiConnected() {
textWifiStatus.setText(R.string.connected);
toggleStartStopServer.setEnabled(true);
}
////////////////////////////////////////////////////////////////////////////////
///////////////////////////// INTERACTION //////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/**
* This methods represents an onClickListener of the start/stop server
* toggle button.
*/
@Click
protected void toggleStartStopServer() {
if (toggleStartStopServer.isChecked())
startServer();
else
stopServer();
}
////////////////////////////////////////////////////////////////////////////////
//////////////////////////////// MENU //////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/**
* This is a representation of an onClickListener of the preferences menu
* button, which starts the preferences activity.
*/
@OptionsItem
protected void menuPreferences() {
startActivity(new Intent(this, OIWiFiPreferencesActivity_.class));
}
////////////////////////////////////////////////////////////////////////////////
/////////////////////////////// SERVER /////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/**
* Starts the actual web server, which will be configured using the app's
* preferences. All request handlers are registered as well as a
* {@link ServerStatusListener}
*/
private void startServer() {
if (mWebServer == null) {
if (prefs.sslEnable().get())
try {
mWebServer = new WebServer(prefs.sslPort().get(), true, getAssets().open("oi.bks"), "openintents".toCharArray());
} catch (IOException e) {
Log.e(TAG, e.toString());
}
else
mWebServer = new WebServer(prefs.port().get());
if (prefs.passwordEnable().get()) {
mWebServer.addRequestInterceptor(new AuthenticationInterceptor());
}
mWebServer.registerRequestHandler("*", FileHandler_.getInstance_(this));
mWebServer.registerRequestHandler("/apps", new AvailableAppsHandler(this));
mWebServer.registerRequestHandler("/notes/get*", new GetNote(this));
mWebServer.registerRequestHandler("/notes/delete*", new DeleteNote(this));
mWebServer.registerRequestHandler("/notes/new", new NewNote(this));
mWebServer.registerRequestHandler("/notes/update", new UpdateNote(this));
mWebServer.registerRequestHandler("/login", LoginHandler_.getInstance_(this));
mWebServer.registerRequestHandler("/logout", new LogoutHandler());
mWebServer.registerRequestHandler("/shoppinglist/list/get*", new GetShoppinglist(this));
mWebServer.registerRequestHandler("/shoppinglist/list/delete*", new DeleteShoppinglist(this));
mWebServer.registerRequestHandler("/shoppinglist/list/new*", new NewShoppinglist(this));
mWebServer.registerRequestHandler("/shoppinglist/list/rename*", new RenameShoppinglist(this));
mWebServer.registerRequestHandler("/shoppinglist/item/get*", new GetItem(this));
mWebServer.registerRequestHandler("/shoppinglist/item/update", new UpdateItem(this));
mWebServer.registerRequestHandler("/shoppinglist/item/delete*", new DeleteItem(this));
mWebServer.addListener(new ServerStatusListener() {
@Override
public void onStatusChanged(Status status, String msg) {
switch (status) {
case ERROR: Toast.makeText(OIWiFiServerActivity.this, "Server Error: "+msg, Toast.LENGTH_LONG).show(); break;
case STARTED: serverStarted(); break;
case STOPPED: serverStopped();
}
}
});
}
mWebServer.start();
}
/**
* Stops the server if it is running.
*/
private void stopServer() {
if (mWebServer != null)
mWebServer.stop();
mWebServer = null;
}
/**
* After the server has been stopped, this method is called, which updates the
* GUI. The server URL is removed and the start/stop toggle button is
* "un-toggled".
*/
private void serverStopped() {
toggleStartStopServer.setChecked(false);
textURL.setText("");
}
/**
* After the server has been started, this method is called. It will show
* the server's URL within the user interface.
*/
private void serverStarted() {
textURL.setText(buildURLString());
}
////////////////////////////////////////////////////////////////////////////////
//////////////////////////////// UTIL //////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/**
* Builds an string which represents the address that can be used with a web
* browser to access the web server.
* The URL has the format <code>http[s]://<i>ip</i>:<i>port</i></code>.
*
* @return The URL which can be used to access the web server.
*/
private String buildURLString() {
return (prefs.sslEnable().get() ? "https" : "http") + "://" + getDeviceIPAddress()+":"+mWebServer.getPort();
}
/**
* Returns the IPv4 address of the device, which will only work when it is
* connected via WiFi. Otherwise "0.0.0.0" will be returned.
*
* @return A string representation of the device's IPv4 address.
*/
private String getDeviceIPAddress() {
WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
int ipAddress = wifiInfo.getIpAddress();
return String.format("%d.%d.%d.%d",
(ipAddress & 0xff),
(ipAddress >> 8 & 0xff),
(ipAddress >> 16 & 0xff),
(ipAddress >> 24 & 0xff));
}
/**
* <p>
* {@inheritDoc}
* </p>
* This method must be overridden to avoid compatibility issues with older
* Android versions.
*/
@Override
public void onBackPressed() {
this.finish();
}
}