diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 96a0120..89bc1ea 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -6,7 +6,7 @@
+ android:targetSdkVersion="19" />
@@ -21,6 +21,7 @@
+
-
+ android:inputType="text" />
+ -->
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 7a7935b..653f02a 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -7,7 +7,7 @@
Cámara abierta exitosamente
La cámara no pudo abrirse
Conectar con NxtAR
- Encender cámara
+ Conectar con dispositivo controlador
CamActivity
Dirección IP de NxtAR
La dirección IP no es válida
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 81d9ef4..03383cc 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -8,7 +8,7 @@
Camera could not be opened
CamActivity
Connect with NxtAR
- Start camera
+ Connect with controller device
NxtAR IP Address
Invalid IP address
Fill out the IP address field
diff --git a/src/ve/ucv/ciens/ccg/nxtcam/CamActivity.java b/src/ve/ucv/ciens/ccg/nxtcam/CamActivity.java
index 514d281..244308f 100644
--- a/src/ve/ucv/ciens/ccg/nxtcam/CamActivity.java
+++ b/src/ve/ucv/ciens/ccg/nxtcam/CamActivity.java
@@ -5,6 +5,7 @@ import ve.ucv.ciens.ccg.nxtcam.network.ImageTransferThread;
import ve.ucv.ciens.ccg.nxtcam.utils.Logger;
import ve.ucv.ciens.ccg.nxtcam.utils.ProjectConstants;
import android.app.Activity;
+import android.content.Intent;
import android.hardware.Camera;
import android.os.AsyncTask;
import android.os.Bundle;
@@ -23,6 +24,7 @@ public class CamActivity extends Activity{
private CameraPreview cPreview;
private CameraSetupTask camSetupTask;
private ImageTransferThread imThread;
+ private String serverIp;
/*******************
* Android methods *
@@ -35,6 +37,9 @@ public class CamActivity extends Activity{
cPreview = new CameraPreview(this, hwCamera);
setContentView(cPreview);
+ Intent intent = getIntent();
+ serverIp = intent.getStringExtra("address");
+
imThread = new ImageTransferThread();
}
diff --git a/src/ve/ucv/ciens/ccg/nxtcam/MainActivity.java b/src/ve/ucv/ciens/ccg/nxtcam/MainActivity.java
index a076766..3f93625 100644
--- a/src/ve/ucv/ciens/ccg/nxtcam/MainActivity.java
+++ b/src/ve/ucv/ciens/ccg/nxtcam/MainActivity.java
@@ -1,13 +1,18 @@
package ve.ucv.ciens.ccg.nxtcam;
+import java.io.IOException;
+import java.net.DatagramPacket;
import java.net.InetAddress;
+import java.net.MulticastSocket;
import java.net.UnknownHostException;
import ve.ucv.ciens.ccg.nxtcam.utils.Logger;
+import ve.ucv.ciens.ccg.nxtcam.utils.ProjectConstants;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.wifi.WifiManager;
+import android.net.wifi.WifiManager.MulticastLock;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
@@ -16,14 +21,32 @@ import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
+/**
+ * Entry point por the NxtCAM application.
+ *
+ * This activity shows a splashscreen and handles the search for the controller device
+ * via a simle ad hoc UDP based service discovery method. Basically, it just listens for
+ * multicast packets sent by the controller device on the multicast address defined in
+ * ProjectConstants.java. When the packet is received the next activity of the application
+ * is launched with the ip address found. The service discovery process continues until a
+ * datagram carrying the string "NxtAR server here!" is received.
+ *
+ * @author miky
+ *
+ */
public class MainActivity extends Activity {
+ // Cosntant fields.
private final String TAG = "NXTCAM_MAIN";
private final String CLASS_NAME = MainActivity.class.getSimpleName();
+ // Gui components.
private Button startButton;
- private TextView ipField;
+ //private TextView ipField;
+ // Resources.
private WifiManager wifiManager;
+
+ // Variables.
private boolean wifiOnByMe;
@Override
@@ -31,35 +54,34 @@ public class MainActivity extends Activity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
+ // Set up fields.
+ wifiOnByMe = false;
+
+ // Set up gui components.
startButton = (Button)findViewById(R.id.startButton);
startButton.setOnClickListener(startClickListener);
+ // ipField = (TextView)findViewById(R.id.ipAddressField);
- ipField = (TextView)findViewById(R.id.ipAddressField);
-
+ // Set up services.
wifiManager = (WifiManager)getSystemService(Context.WIFI_SERVICE);
-
- if(!wifiManager.isWifiEnabled()) setWifi(true);
+ if(!wifiManager.isWifiEnabled())
+ setWifi(true);
}
@Override
public void onResume(){
super.onResume();
- if(!wifiManager.isWifiEnabled()) setWifi(true);
+ if(!wifiManager.isWifiEnabled())
+ setWifi(true);
}
@Override
public void onPause(){
super.onPause();
- if(wifiManager.isWifiEnabled() && wifiOnByMe) setWifi(false);
- }
-
- @Override
- public void onDestroy(){
- super.onDestroy();
-
- if(wifiManager.isWifiEnabled() && wifiOnByMe) wifiManager.setWifiEnabled(false);
+ if(wifiManager.isWifiEnabled() && wifiOnByMe)
+ setWifi(false);
}
@Override
@@ -69,10 +91,17 @@ public class MainActivity extends Activity {
return true;
}
- private void startCamActivity(boolean canStart){
- if(canStart){
+ /**
+ * Start the camera capture activity if a server was found through service discovery.
+ *
+ * @param serverFound Indicates if a server was found, doh!
+ * @param ipAddress The ip address of the server.
+ */
+ private void startCamActivity(boolean serverFound, String ipAddress){
+ if(serverFound){
Logger.log(Logger.LOG_TYPES.DEBUG, TAG, CLASS_NAME + ".startCamActivity() :: Launching camera activity.");
Intent intent = new Intent(this, CamActivity.class);
+ intent.putExtra("address", ipAddress);
startActivity(intent);
}else{
Logger.log(Logger.LOG_TYPES.DEBUG, TAG, CLASS_NAME + ".startCamActivity() :: Cannot launch camera activity.");
@@ -80,16 +109,21 @@ public class MainActivity extends Activity {
}
}
- private void setWifi(boolean on){
- wifiManager.setWifiEnabled(on);
- Logger.log(Logger.LOG_TYPES.DEBUG, TAG, CLASS_NAME + ".ImageTransferThread() :: setting wifi to " + (on ? "on" : "off"));
- if(on)
+ /**
+ * Sets the state of the device's WiFi radio.
+ *
+ * @param radioState The state to set the radio to; true for on, false for off.
+ */
+ private void setWifi(boolean radioState){
+ wifiManager.setWifiEnabled(radioState);
+ Logger.log(Logger.LOG_TYPES.DEBUG, TAG, CLASS_NAME + ".setWifi() :: setting wifi to " + (radioState ? "on" : "off"));
+ if(radioState)
wifiOnByMe = true;
else
wifiOnByMe = false;
}
- private void validateIpAddress(){
+ /*private void validateIpAddress(){
if(ipField.getText().toString().compareTo("") != 0){
Logger.log(Logger.LOG_TYPES.DEBUG, TAG, CLASS_NAME + "validateIpAddress() :: Launching verification task.");
VerifyIpAddressTask verifyIp = new VerifyIpAddressTask();
@@ -98,16 +132,93 @@ public class MainActivity extends Activity {
Logger.log(Logger.LOG_TYPES.DEBUG, TAG, CLASS_NAME + "validateIpAddress() :: Ip address field is empty.");
Toast.makeText(this, R.string.emptyIpToast, Toast.LENGTH_SHORT).show();
}
- }
+ }*/
+ /**
+ * Event listener for the connection button.
+ */
private final View.OnClickListener startClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
- validateIpAddress();
+ //validateIpAddress();
+ ServiceDiscoveryTask serviceDiscovery = new ServiceDiscoveryTask();
+ serviceDiscovery.execute();
}
};
- private class VerifyIpAddressTask extends AsyncTask{
+ /**
+ * Asynchronous task for ad hoc UDP service discovery.
+ *
+ * @author Miguel Angel Astor Romero
+ */
+ private class ServiceDiscoveryTask extends AsyncTask{
+
+ private final String CLASS_NAME = ServiceDiscoveryTask.class.getSimpleName();
+
+ private MulticastSocket udpSocket;
+ private DatagramPacket packet;
+ private MulticastLock multicastLock;
+
+ public ServiceDiscoveryTask(){
+ // Open a multicast socket and join the project's multicast group.
+ try{
+ udpSocket = new MulticastSocket(ProjectConstants.SERVER_UDP_PORT);
+ InetAddress group = InetAddress.getByName(ProjectConstants.MULTICAST_ADDRESS);
+ udpSocket.joinGroup(group);
+ }catch(IOException io){
+ Logger.log(Logger.LOG_TYPES.ERROR, TAG ,CLASS_NAME + ".ServiceDiscoveryTask() :: " + io.getMessage());
+ }
+ }
+
+ @Override
+ protected Boolean doInBackground(Void... params){
+ boolean result, done = false;
+ byte[] buffer = (new String("Server is here")).getBytes();
+
+ // Create a buffer and tell Android we want to receive multicast datagrams.
+ packet = new DatagramPacket(buffer, buffer.length);
+ multicastLock = wifiManager.createMulticastLock(TAG);
+ multicastLock.setReferenceCounted(true);
+ multicastLock.acquire();
+
+ // Listen for a UDP datagram on the multicast group.
+ // If the datagram received contains a string with it's content equal to "NxtAR server here!"
+ // then assume the server found is a valid controller device.
+ try{
+ while(!done){
+ udpSocket.receive(packet);
+ Logger.log(Logger.LOG_TYPES.DEBUG, TAG, CLASS_NAME + ".run() :: Found a server at " + packet.getAddress().getHostAddress());
+ String received = new String(packet.getData());
+ if(received.compareTo("NxtAR server here!") == 0)
+ done = true;
+ }
+ result = true;
+ }catch(IOException io){
+ Logger.log(Logger.LOG_TYPES.ERROR, TAG, CLASS_NAME + ".doInBackground() :: " + io.getMessage());
+ result = false;
+ }
+
+ // Tell Android we do not want to receive more UDP datagrams to save battery life.
+ if(multicastLock != null){
+ multicastLock.release();
+ multicastLock = null;
+ }
+
+ return result;
+ }
+
+ @Override
+ protected void onPostExecute(Boolean result){
+ super.onPostExecute(result);
+ // If a server was found then start the next activity.
+ if(packet != null)
+ startCamActivity(result, packet.getAddress().getHostAddress());
+ else
+ startCamActivity(false, null);
+ }
+ };
+
+ /* private class VerifyIpAddressTask extends AsyncTask{
private final String CLASS_NAME = VerifyIpAddressTask.class.getSimpleName();
@Override
@@ -127,5 +238,5 @@ public class MainActivity extends Activity {
super.onPostExecute(result);
startCamActivity(result);
}
- };
+ };*/
}
diff --git a/src/ve/ucv/ciens/ccg/nxtcam/network/ServiceDiscoveryThread.java b/src/ve/ucv/ciens/ccg/nxtcam/network/ServiceDiscoveryThread.java
deleted file mode 100644
index 48b960f..0000000
--- a/src/ve/ucv/ciens/ccg/nxtcam/network/ServiceDiscoveryThread.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package ve.ucv.ciens.ccg.nxtcam.network;
-
-public class ServiceDiscoveryThread extends Thread {
-
- public ServiceDiscoveryThread(){
-
- }
-
- @Override
- public void run(){
-
- }
-}
diff --git a/src/ve/ucv/ciens/ccg/nxtcam/utils/ProjectConstants.java b/src/ve/ucv/ciens/ccg/nxtcam/utils/ProjectConstants.java
index 6a29166..aed7b89 100644
--- a/src/ve/ucv/ciens/ccg/nxtcam/utils/ProjectConstants.java
+++ b/src/ve/ucv/ciens/ccg/nxtcam/utils/ProjectConstants.java
@@ -5,5 +5,7 @@ public abstract class ProjectConstants {
public static final int SERVER_TCP_PORT_1 = 9989;
public static final int SERVER_TCP_PORT_2 = 9990;
+ public static final String MULTICAST_ADDRESS = "230.0.0.1";
+
public static final boolean DEBUG = true;
}