Related
I'm using package com.hierynomus.smbj.share; to connect via smb2 to a network location in order to check it's connectivity however this only runs at the start of my activity (in background).
I've added a listener to return after the task has returned a string value (fail, success) once the the listener in the activity (i called the task from) is called, I then create a new instance of the Connection Status (this loops it)
This is how i check for the connection at onCreate() of an activity
//Global ConnectionStatus connectionStatus;
connectionStatus = new ConnectionStatus();
connectionStatus.setContext(this);
connectionStatus.setListener(this);
connectionStatus.setCon(databaseReadWrite.getMydbc());
connectionStatus.execute("CheckDatabase", "nodelay");
This is how I'm trying to cancel task when another activity is opened
protected void onPause() {
delay.equals("cancel");
super.onPause();
MyApplication.activityPaused();
if (connectionStatus != null) {
connectionStatus.cancel(true);
}
hasRun = false;
}
Then this runs in the same activity after the async task is completed so i've re-run a new instance of connectionStatus
#Override
public void onTaskCompleted(String result) {
ActionBar actionBar = this.getSupportActionBar();
String title = getTitle().toString();
String code = handlingFunctions.getResultCode(result);
if (code.equals("1")) {
Message.message(this, " Database connected to server!");
setTitle(title + result);
} else if (code.equals("2")) {
actionBar.setBackgroundDrawable(new ColorDrawable(Color.RED));
alertDialog.message(this, result);
} else if (code.equals("0")) {
actionBar.setBackgroundDrawable(new ColorDrawable(Color.RED));
setTitle(title + " Database connected in offline mode");
alertDialog.message(this, result);
} else if (code.equals("3")) {
//alertDialog.message(this, result);
imageStatus.setText(result);
} else if (code.equals("4")) {
imageStatus.setText(result);
}
connectionStatus = new ConnectionStatus();
connectionStatus.setContext(getApplicationContext());
connectionStatus.setListener(AllParts.this);
connectionStatus.setCon(databaseReadWrite.getMydbc());
connectionStatus.execute("CheckDatabase", "delay");
}
}
public class ConnectionStatus extends AsyncTask<String, Void, String> {
private OnConnectionStatusComplete listener;
private ArrayList<String> imageNames;
private ArrayList<ImageDetails> currentImageDetails;
private SQLiteConnection sqLiteConnection;
private Context context;
public void setListener(OnConnectionStatusComplete listen) {
this.listener = listen;
}
public void setImageNames(ArrayList<String> ImageNames) {
this.imageNames = ImageNames;
}
public void setCurrentDetails(ArrayList<ImageDetails> details) {
this.currentImageDetails = details;
}
#Override
protected void onPostExecute(String s) {
listener.onTaskCompleted(s);
}
public void setContext(Context mContext) {
context = mContext;
}
public void setCon(SQLiteConnection sqlite) {
sqLiteConnection = sqlite;
}
#Override
protected String doInBackground(String... strings) {
if(this.isCancelled()){
return "";
}else{
MyApplication myApplication = (MyApplication) context.getApplicationContext();
String IPAddress = myApplication.getIpaddress();
String domain = myApplication.getDomainname();
String username = myApplication.getUsername();
String password = myApplication.getPassword();
String containingFolder = myApplication.getSharefolder();
String temp = "";
//return null;
if (strings[1].equals("delay")) {
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (strings[0].equals("CheckDatabase")) {
temp = checkDatabaseConnect();
} else {
temp = checkImageConnection(IPAddress, domain, username, password, containingFolder);
}
return temp;
}
}
String checkDatabaseConnect() {
String statement = "PRAGMA sync_status";
JSONArray is_ready = new JSONArray();
try {
SQLiteStatement mystatement = null;
try {
mystatement = sqLiteConnection.prepareStatement(statement);
} catch (SQLException ex) {
try {
java.io.File path = new java.io.File("/sdcard/exports/logs");
SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
String currentDateTime = dateFormat.format(new Date()) + " ";
java.io.File myFile = new java.io.File(path, "DBCrashes.txt");
FileOutputStream fOut = new FileOutputStream(myFile, true);
OutputStreamWriter myOutWriter = new OutputStreamWriter(fOut);
myOutWriter.append("\n" +
"\r");
myOutWriter.append(currentDateTime + "Get pragma results: (" + statement + ")" + ex);
myOutWriter.close();
fOut.close();
} catch (java.io.IOException e) {
//do something if an IOException occurs.
}
}
mystatement.step();
int ncols = mystatement.getColumnCount();
if (ncols > 0) {
String result = mystatement.getColumnTextNativeString(0);
JSONObject jObject = new JSONObject(result);
is_ready = jObject.getJSONArray("peers");
if (is_ready.length() > 0) {
return "Success, Database is connected! (1)";
} else {
return "The database is not connected to the server. In offline mode, check network and restart application to connect to server. (0)";
}
}
mystatement.dispose();
} catch (SQLException ex) {
try {
java.io.File path = new java.io.File("/sdcard/exports/logs");
SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
String currentDateTime = dateFormat.format(new Date()) + " ";
java.io.File myFile = new java.io.File(path, "DBCrashes.txt");
FileOutputStream fOut = new FileOutputStream(myFile, true);
OutputStreamWriter myOutWriter = new OutputStreamWriter(fOut);
myOutWriter.append("\n" +
"\r");
myOutWriter.append(currentDateTime + " (" + statement + ")" + ex);
myOutWriter.close();
fOut.close();
return "No connection to a database, please try again (2)";
} catch (java.io.IOException e) {
//do something if an IOException occurs.
}
} catch (JSONException e) {
e.printStackTrace();
}
return "Success (5)";
}
}
The problem I'm having is after I leave the activity, the task is still running and returns this error (I know this because it takes into account the delay)
You do have implemented a handling for isCanceled but this implementation is only at the start.
Your current flow is like this:
task starts, immediately checks if it is cancelled or not (since it is the first line in doInBackground)
onPause is called, cancel of the task is invoked
since the cancel check has already been made your task continues to run freely
How do you solve this?
The easiest way would be to check if it is cancelled before checkDatabaseConnection or checkImageConnection is called. And even inside those methods check if it is cancelled or not.
Even if that is done correctly, your Thread.sleep could cause your AsyncTask being cancelled 6s after onPause is called.
For reasons like this, AsyncTask is not used anymore. There are other options for Threading which are much better.
This or this will give you a starting point.
try checking if the task is cancelled after the Thread.sleep(6000) , so even if the task was in sleep when cancel is called it will return when it is done.
if (strings[1].equals("delay")) {
try {
Thread.sleep(6000);
if(this.isCancelled()) {
return "";
}
} catch (InterruptedException e) {
e.printStackTrace();
}
/*if(this.isCancelled()) {
return "";
}*/
}
I know this kind of questions are maybe too old, but I got stock with this silly thing.
I have an AsyncTask class which is a subclass of an activity class, and right now I want to call it from another class: following codes shows what I mean:
public class STA extends Activity {
public class ListSpdFiles extends AsyncTask<Void, Void, String[]> {
private static final String TAG = "ListSpdFiles: ";
/**
* Status code returned by the SPD on operation success.
*/
private static final int SUCCESS = 4;
private String initiator;
private String path;
private SecureApp pcas;
private boolean isConnected = false; // connected to PCAS service?
private PcasConnection pcasConnection = new PcasConnection() {
#Override
public void onPcasServiceConnected() {
Log.d(TAG, "pcasServiceConnected");
latch.countDown();
}
#Override
public void onPcasServiceDisconnected() {
Log.d(TAG, "pcasServiceDisconnected");
}
};
private CountDownLatch latch = new CountDownLatch(1);
public ListSpdFiles(String initiator, String path) {
this.initiator = initiator;
this.path = path;
}
private void init() {
Log.d(TAG, "starting task");
pcas = new AndroidNode(getApplicationContext(), pcasConnection);
isConnected = pcas.connect();
}
private void term() {
Log.d(TAG, "terminating task");
if (pcas != null) {
pcas.disconnect();
pcas = null;
isConnected = false;
}
}
#Override
protected void onPreExecute() {
super.onPreExecute();
init();
}
#Override
protected String[] doInBackground(Void... params) {
// check if connected to PCAS Service
if (!isConnected) {
Log.v(TAG, "not connected, terminating task");
return null;
}
// wait until connection with SPD is up
try {
if (!latch.await(20, TimeUnit.SECONDS)) {
Log.v(TAG, "unable to connected within allotted time, terminating task");
return null;
}
} catch (InterruptedException e) {
Log.v(TAG, "interrupted while waiting for connection in lsdir task");
return null;
}
// perform operation (this is where the actual operation is called)
try {
return lsdir();
} catch (DeadServiceException e) {
Log.i(TAG, "service boom", e);
return null;
} catch (DeadDeviceException e) {
Log.i(TAG, "device boom", e);
return null;
}
}
#Override
protected void onPostExecute(String[] listOfFiles) {
super.onPostExecute(listOfFiles);
if (listOfFiles == null) {
Log.i(TAG, "task concluded with null list of files");
// tv.setText("task concluded with a null list of files");
} else {
Log.i(TAG, "task concluded with the following list of files: "
+ Arrays.toString(listOfFiles));
//tv.setText("List of files received is:\n" + Arrays.toString(listOfFiles));
}
term();
}
#Override
protected void onCancelled(String[] listOfFiles) {
super.onCancelled(listOfFiles);
Log.i(TAG, "lsdir was canceled");
term();
}
/**
* Returns an array of strings containing the files available at the given path, or
* {#code null} on failure.
*/
private String[] lsdir() throws DeadDeviceException, DeadServiceException {
Result<List<String>> result = pcas.lsdir(initiator, path); // the lsdir call to the
final Global globalVariable = (Global) getApplicationContext();
if (globalVariable.getPasswordButt() == false) {
// Calling Application class (see application tag in AndroidManifest.xml)
// Get name and email from global/application context
final boolean isusername = globalVariable.getIsUsername();
if (isusername == true) {
String username = "/" + getLastAccessedBrowserPage() + ".username" + ".txt";
//String password = "/" + CurrentURL + "password" + ".txt";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
pcas.readFile(initiator, username, baos);
Log.i(TAG, "OutputStreampassword: "
+ new String(baos.toByteArray()));
String name = new String(baos.toByteArray());
if (!name.equalsIgnoreCase("")) {
globalVariable.setUsername(name);
// getCurrentInputConnection().setComposingText(name, 1);
// updateCandidates();
}
globalVariable.setIsUsername(false);
} else if (isusername == false)
Log.i(TAG, "Wrong Input Type For Username.");
// globalVariable.setUsernameButt(false);
} else if (globalVariable.getPasswordButt() == true) {
// Calling Application class (see application tag in AndroidManifest.xml)
// final Global globalVariable = (Global) getApplicationContext();
// Get name and email from global/application context
final boolean ispassword = globalVariable.getIsPassword();
if (ispassword == true) {
// String username = "/" + CurrentURL + "username" + ".txt";
String password = "/" + getLastAccessedBrowserPage() + ".password" + ".txt";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
pcas.readFile(initiator, password, baos);
Log.i(TAG, "OutputStreampassword: "
+ new String(baos.toByteArray()));
String name = new String(baos.toByteArray());
if (!name.equalsIgnoreCase("")) {
globalVariable.setPassword(name);
//getCurrentInputConnection().setComposingText(name, 1);
// updateCandidates();
}
globalVariable.setIsPassword(false);
} else if (ispassword == false)
Log.i(TAG, "Wrong Input Type For Password.");
globalVariable.setPasswordButt(false);
// boolpassword=false;
}
//}
if (result.getState() != SUCCESS) {
Log.v(TAG, "operation failed");
return null;
}
if (result.getValue() == null) {
Log.v(TAG, "operation succeeded but operation returned null list");
return null;
}
return result.getValue().toArray(new String[0]);
}
}
public String getLastAccessedBrowserPage() {
String Domain = null;
Cursor webLinksCursor = getContentResolver().query(Browser.BOOKMARKS_URI, Browser.HISTORY_PROJECTION, null, null, Browser.BookmarkColumns.DATE + " DESC");
int row_count = webLinksCursor.getCount();
int title_column_index = webLinksCursor.getColumnIndexOrThrow(Browser.BookmarkColumns.TITLE);
int url_column_index = webLinksCursor.getColumnIndexOrThrow(Browser.BookmarkColumns.URL);
if ((title_column_index > -1) && (url_column_index > -1) && (row_count > 0)) {
webLinksCursor.moveToFirst();
while (webLinksCursor.isAfterLast() == false) {
if (webLinksCursor.getInt(Browser.HISTORY_PROJECTION_BOOKMARK_INDEX) != 1) {
if (!webLinksCursor.isNull(url_column_index)) {
Log.i("History", "Last page browsed " + webLinksCursor.getString(url_column_index));
try {
Domain = getDomainName(webLinksCursor.getString(url_column_index));
Log.i("Domain", "Last page browsed " + Domain);
return Domain;
} catch (URISyntaxException e) {
e.printStackTrace();
}
break;
}
}
webLinksCursor.moveToNext();
}
}
webLinksCursor.close();
return null;
}
public String getDomainName(String url) throws URISyntaxException {
URI uri = new URI(url);
String domain = uri.getHost();
return domain.startsWith("www.") ? domain.substring(4) : domain;
}}
Would you please tell me what should I do to fix this code?
Looking over the code I did not see anywhere you referenced anything from the Activity itself besides the application context so you can move the ListSpdFiles class to its own java file and pass it a context into the constructor when you make a new instance of it.
Put this class in a ListSpdFiles.java file so it is no longer an inner class.
public class ListSpdFiles extends AsyncTask<Void, Void, String[]> {
Context applicationContext;
public ListSpdFiles(Context context, String initiator, String path) {
this.initiator = initiator;
this.path = path;
applicationContext = context.getApplicationContext();
}
// The rest of your code still goes here. Replace other calls to
// getApplicationContext() with the new applicationContext field
}
You can now use this class anywhere a Context is available. You create a new instance by doing:
ListSpdFiles listSpdFilesTask = new ListSpdFiles(context, "someInitiator", "somePath");
listSpdFilesTask.execute();
I am working on Brix android x86 system. After inserting a module(introduced memory crashed code in the module for causing panic), it panics. But, the system does not auto-reboot. It hangs. Could you please tell the steps for auto-rebooting the android after panic ?
Thanks And Regards,
Pankaj
Depending upon your requirement you can put these peice of code where you require.
You can do with these 2 scenarios
You application must be signed with system application
// must be a system app
void reboot(Context context) {
PowerManager pm = (PowerManager) context
.getSystemService(Context.POWER_SERVICE);
pm.reboot(null);
}
You device must be rooted
if (ShellInterface.isSuAvailable()) {
ShellInterface.runCommand("-su");
ShellInterface.runCommand("reboot");
}
ShellInterface.class
public class ShellInterface {
private static final String TAG = "ShellInterface";
private static String shell;
// uid=0(root) gid=0(root)
private static final Pattern UID_PATTERN = Pattern
.compile("^uid=(\\d+).*?");
enum OUTPUT {
STDOUT, STDERR, BOTH
}
private static final String EXIT = "exit\n";
private static final String[] SU_COMMANDS = new String[] { "su",
"/system/xbin/su", "/system/bin/su" };
private static final String[] TEST_COMMANDS = new String[] { "id",
"/system/xbin/id", "/system/bin/id" };
public static synchronized boolean isSuAvailable() {
if (shell == null) {
checkSu();
}
return shell != null;
}
public static synchronized void setShell(String shell) {
ShellInterface.shell = shell;
}
private static boolean checkSu() {
for (String command : SU_COMMANDS) {
shell = command;
if (isRootUid())
return true;
}
shell = null;
return false;
}
private static boolean isRootUid() {
String out = null;
for (String command : TEST_COMMANDS) {
out = getProcessOutput(command);
if (out != null && out.length() > 0)
break;
}
if (out == null || out.length() == 0)
return false;
Matcher matcher = UID_PATTERN.matcher(out);
if (matcher.matches()) {
if ("0".equals(matcher.group(1))) {
return true;
}
}
return false;
}
public static String getProcessOutput(String command) {
try {
return _runCommand(command, OUTPUT.STDERR);
} catch (IOException ignored) {
return null;
}
}
public static boolean runCommand(String command) {
try {
_runCommand(command, OUTPUT.BOTH);
return true;
} catch (IOException ignored) {
return false;
}
}
private static String _runCommand(String command, OUTPUT o)
throws IOException {
DataOutputStream os = null;
Process process = null;
try {
process = Runtime.getRuntime().exec(shell);
os = new DataOutputStream(process.getOutputStream());
InputStreamHandler sh = sinkProcessOutput(process, o);
os.writeBytes(command + '\n');
os.flush();
os.writeBytes(EXIT);
os.flush();
process.waitFor();
if (sh != null) {
String output = sh.getOutput();
Log.d(TAG, command + " output: " + output);
return output;
} else {
return null;
}
} catch (Exception e) {
final String msg = e.getMessage();
Log.e(TAG, "runCommand error: " + msg);
throw new IOException(msg);
} finally {
try {
if (os != null) {
os.close();
}
if (process != null) {
process.destroy();
}
} catch (Exception ignored) {
}
}
}
public static InputStreamHandler sinkProcessOutput(Process p, OUTPUT o) {
InputStreamHandler output = null;
switch (o) {
case STDOUT:
output = new InputStreamHandler(p.getErrorStream(), false);
new InputStreamHandler(p.getInputStream(), true);
break;
case STDERR:
output = new InputStreamHandler(p.getInputStream(), false);
new InputStreamHandler(p.getErrorStream(), true);
break;
case BOTH:
new InputStreamHandler(p.getInputStream(), true);
new InputStreamHandler(p.getErrorStream(), true);
break;
}
return output;
}
private static class InputStreamHandler extends Thread {
private final InputStream stream;
private final boolean sink;
StringBuffer output;
public String getOutput() {
return output.toString();
}
InputStreamHandler(InputStream stream, boolean sink) {
this.sink = sink;
this.stream = stream;
start();
}
#Override
public void run() {
try {
if (sink) {
while (stream.read() != -1) {
}
} else {
output = new StringBuffer();
BufferedReader b = new BufferedReader(
new InputStreamReader(stream));
String s;
while ((s = b.readLine()) != null) {
output.append(s);
}
}
} catch (IOException ignored) {
}
}
}
}
You can force the kernel panic with "echo c > /proc/sysrq-trigger" command.
More debug logs can be seen via kernel panic log.
I am making my first PhoneGap app for Android and it needs mDNS resolution. As ".local" addresses are not resolved on Android (before v4.1), I have used a ZeroConf library with JmDNS.jar file. I have taken reference for plugin from this GitHub repository, you might wanna have a look.
ZeroConf.java
public PluginResult execute(String action, JSONArray args, String callbackId) {
this.callback = callbackId;
if (action.equals("watch")) {
String type = args.optString(0);
if (type != null) {
watch(type);
} else {
return new PluginResult(PluginResult.Status.ERROR, "Service type not specified");
}
} else if (action.equals("unwatch")) {
String type = args.optString(0);
if (type != null) {
unwatch(type);
} else {
return new PluginResult(PluginResult.Status.ERROR, "Service type not specified");
}
} else if (action.equals("register")) {
JSONObject obj = args.optJSONObject(0);
if (obj != null) {
String type = obj.optString("type");
String name = obj.optString("name");
int port = obj.optInt("port");
String text = obj.optString("text");
if(type == null) {
return new PluginResult(PluginResult.Status.ERROR, "Missing required service info");
}
register(type, name, port, text);
} else {
return new PluginResult(PluginResult.Status.ERROR, "Missing required service info");
}
} else if (action.equals("close")) {
if(jmdns != null) {
try {
jmdns.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} else if (action.equals("unregister")) {
if(jmdns != null) {
jmdns.unregisterAllServices();
}
} else {
Log.e("ZeroConf", "Invalid action: " + action);
return new PluginResult(PluginResult.Status.INVALID_ACTION);
}
PluginResult result = new PluginResult(Status.NO_RESULT);
result.setKeepCallback(true);
return result;
}
private void watch(String type) {
if(jmdns == null) {
setupWatcher();
}
Log.d("ZeroConf", "Watch " + type);
Log.d("ZeroConf", "Name: " + jmdns.getName() + " host: " + jmdns.getHostName());
jmdns.addServiceListener(type, listener);
}
private void unwatch(String type) {
if(jmdns == null) {
return;
}
jmdns.removeServiceListener(type, listener);
}
private void register (String type, String name, int port, String text) {
if(name == null) {
name = "";
}
if(text == null) {
text = "";
}
try {
ServiceInfo service = ServiceInfo.create(type, name, port, text);
jmdns.registerService(service);
} catch (IOException e) {
e.printStackTrace();
}
}
private void setupWatcher() {
Log.d("ZeroConf", "Setup watcher");
WifiManager wifi = (WifiManager) this.cordova.getActivity().getSystemService(android.content.Context.WIFI_SERVICE);
lock = wifi.createMulticastLock("ZeroConfPluginLock");
lock.setReferenceCounted(true);
lock.acquire();
try {
jmdns = JmDNS.create();
listener = new ServiceListener() {
public void serviceResolved(ServiceEvent ev) {
Log.d("ZeroConf", "Resolved");
sendCallback("added", ev.getInfo());
}
public void serviceRemoved(ServiceEvent ev) {
Log.d("ZeroConf", "Removed");
sendCallback("removed", ev.getInfo());
}
public void serviceAdded(ServiceEvent event) {
Log.d("ZeroConf", "Added");
// Force serviceResolved to be called again
jmdns.requestServiceInfo(event.getType(), event.getName(), 1);
}
};
} catch (IOException e) {
e.printStackTrace();
return;
}
}
public void sendCallback(String action, ServiceInfo info) {
JSONObject status = new JSONObject();
try {
status.put("action", action);
status.put("service", jsonifyService(info));
Log.d("ZeroConf", "Sending result: " + status.toString());
PluginResult result = new PluginResult(PluginResult.Status.OK, status);
result.setKeepCallback(true);
this.success(result, this.callback);
} catch (JSONException e) {
e.printStackTrace();
}
}
public static JSONObject jsonifyService(ServiceInfo info) {
JSONObject obj = new JSONObject();
try {
obj.put("application", info.getApplication());
obj.put("domain", info.getDomain());
obj.put("port", info.getPort());
obj.put("name", info.getName());
obj.put("server", info.getServer());
obj.put("description", info.getNiceTextString());
obj.put("protocol", info.getProtocol());
obj.put("qualifiedname", info.getQualifiedName());
obj.put("type", info.getType());
JSONArray addresses = new JSONArray();
String[] add = info.getHostAddresses();
for(int i = 0; i < add.length; i++) {
addresses.put(add[i]);
}
obj.put("addresses", addresses);
JSONArray urls = new JSONArray();
String[] url = info.getURLs();
for(int i = 0; i < url.length; i++) {
urls.put(url[i]);
}
obj.put("urls", urls);
} catch (JSONException e) {
e.printStackTrace();
return null;
}
return obj;
}
ZeroConf.js
var ZeroConf = {
watch: function(type, callback) {
return cordova.exec(function(result) {
if(callback) {
callback(result);
}
}, ZeroConf.fail, "ZeroConf", "watch", [type]);
},
unwatch: function(type) {
return cordova.exec(null, ZeroConf.fail, "ZeroConf", "unwatch", [type]);
},
close: function() {
return cordova.exec(null, ZeroConf.fail, "ZeroConf", "close", [])
},
register: function(type, name, port, text) {
if(!type) {
console.error("'type' is a required field");
return;
}
return cordova.exec(null, ZeroConf.fail, "ZeroConf", "register", [type, name, port, text]);
}
unregister: function() {
return cordova.exec(null, ZeroConf.fail, "ZeroConf", "unregister", [])
},
fail: function (o) {
console.error("Error " + JSON.stringify(o));
}
}
config.xml
<plugins>
<plugin name="ZeroConf" value="com.triggertrap.ZeroConf"/>
</plugins>
NOW MY QUESTION:
I want to call a fixed URL, for example, http://foo.local/abc/ in index.html page and it should resolve to the local IP Address. How do I achieve this? I know it has to be done using JavaScript, but how to go about it? I have searched many many articles and reached till here. I would appreciate if you could guide me a little further.
Somewhere after you receive the 'device ready' event you can register to watch for services advertised over bonjour:
ZeroConf.watch("_http._tcp.local.", function (service) {
// do something with the service
}
However, using the ZeroConf plugin is not enough as you also need the server that serves content at foo.local to advertise its HTTP service over bonjour. If you use a node.js server you can use this module.
This might be a complex problem with my application but I'll do my best to describe it as accurately as I can.
I am making an Android Client and making use of a couple of helper classes someone else handed to me at work. The helper Android classes are called TcpClient.java and PVDCAndroidClient.java. PVDCAndroidClient.java makes use out of the TcpCLient, using a tcpCLient object to connect via serverIP and port.
Here is PVDCAndroidClient.java:
public class PVDCAndroidClient {
// constants
public static final String DEFAULT_LOGIN_URI = "http://me.net:8000/";
private TcpClient tcpClient = null;
private UdpClient udpClient = null;
private boolean connected = false;
private boolean loggedin = false;
private static SimpleDateFormat sdf;
private String loginURI = DEFAULT_LOGIN_URI;
private int getUserNumber;
TcpMessageListener listener = null;
/**
* Connects to proxy server, blocks until complete or timeout
* #param serverIP
* #param port
*/
public void connect(String serverIP, int port)
{
try
{
if(serverIP.length() != 0 && port != 0)
{
tcpClient = new TcpClient();
tcpClient.addTcpListener(listener);
tcpClient.connect(serverIP, port);
}
}
catch(Exception e)
{
e.printStackTrace();
Log.d("Could not connect to server, possbile timeout...", "error");
}
}
///// Make login function a blocking call
// Default login, use last location as login location
public boolean login(String fName, String lName, String password)
{
return this.login(fName, lName, password, "last location");
}
public boolean login(String fName, String lName, String password, String region)
{
return this.login(fName, lName, password, "last location", 128, 128, 20);
}
public boolean login(String fName, String lName, String password, String region, int loginX, int loginY, int loginZ)
{ sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US);
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
// Check passed values
// x, y and z should be between [0, 256]
// strings should not be null or empty(except lName which can be empty)
if((loginX >= 0 && loginX <= 256) && (loginY >=0 && loginY <= 256) && (loginZ >= 0 && loginZ <= 256))
{
if(fName.length() != 0 && fName != null)
{
// Construct packet xml structure
// Send request and wait until reply or timeout
// return false if timeout (or throw exception?)
// if not timeout, read result packet and determine return value
// getUserNumber = tcpClient.getUserNum();
StringWriter stringWriter = new StringWriter();
XmlSerializer serializer = Xml.newSerializer();
try {
serializer.setOutput(stringWriter);
// Indentation is not required, but helps with reading
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
// TODO: Remove hardcoding of strings, make either constants or place in strings.xml
// TODO: Move the header construction to other method as it is fairly constant other than request num and no need to repeat that much code
serializer.startTag("", "pvdc_pkt");
serializer.startTag("", "pvdc_header");
// TODO: replace this with a string unique to the system
serializer.startTag("", "ID");
serializer.text("838393djdjdjd");
serializer.endTag("", "ID");
// TODO: replace this with actual user number from server
serializer.startTag("", "user_num");
serializer.text("22");//get userNum from above
serializer.endTag("", "user_num");
// TODO: add a request number counter to increment this on each request
serializer.startTag("", "request_num");
serializer.text("1");
serializer.endTag("", "request_num");
serializer.startTag("", "DateTime");
serializer.text(sdf.toString()); //utc time variable.
serializer.endTag("", "DateTime");
serializer.endTag("", "pvdc_header");
serializer.startTag("", "pvdc_content");
serializer.attribute("", "type", "requestlogin");
serializer.startTag("", "name");
serializer.attribute("", "fname", fName);
serializer.attribute("", "lname", lName);
serializer.endTag("", "name");
serializer.startTag("", "password");
serializer.text(password);
serializer.endTag("", "password");
serializer.startTag("", "server");
serializer.text(this.loginURI);
serializer.endTag("", "server");
serializer.startTag("", "location");
serializer.attribute("", "region", region);
serializer.text(loginX + ";" + loginY +";" + loginZ);
serializer.endTag("", "location");
serializer.endTag("", "pvdc_content");
serializer.endTag("", "pvdc_pkt");
// Finish writing
serializer.endDocument();
// write xml data out
serializer.flush();
//
sendLogin(stringWriter);
} catch (Exception e) {
Log.e("Exception", "error occurred while creating xml file");
return false;
}
// Print out xml for debugging
Log.d("PVDCAndroidClient Login", stringWriter.toString().trim());
}
else
{
Log.d("Error in name checking", "fName either blank or null");
}
}
else
{
Log.d("login coordinates X,Y, or Z not between 0-256", "Coordinates Error");
}
return true;
}
// moveString should contain the properly formatted movement command(s)[see above move request description]
public void sendLogin(StringWriter stringWriter)
{
tcpClient.sendMessage(stringWriter.toString());
}
}
Here is the actual TcpClient.java:
public class TcpClient {
public interface TcpMessageListener{
public void onMessage(TcpClient client, String message);
}
private Socket socket = null;
private PrintWriter out = null;
private BufferedReader in = null;
private Thread listenThread = null;
private boolean listening = false;
private int userNum = -1;
private List<TcpMessageListener> listeners = new ArrayList<TcpMessageListener>();
public int getUserNum()
{
return this.userNum;
}
public TcpClient() {
}
public void addTcpListener(TcpMessageListener listener)
{
synchronized(this.listeners)
{
this.listeners.add(listener);
}
}
public void removeTcpListener(TcpMessageListener listener)
{
synchronized(this.listeners)
{
this.listeners.remove(listener);
}
}
public boolean connect(String serverIpOrHost, int port) {
try {
socket = new Socket(serverIpOrHost, port);
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
this.listenThread = new Thread(new Runnable(){
public void run() {
int charsRead = 0;
char[] buff = new char[4096];
while(listening && charsRead >= 0)
{
try {
charsRead = in.read(buff);
if(charsRead > 0)
{
Log.d("TCPClient",new String(buff).trim());
String input = new String(buff).trim();
synchronized(listeners)
{
for(TcpMessageListener l : listeners){
l.onMessage(TcpClient.this, input);
}
}
if (input.toLowerCase().contains("<user_num>")){
int index = input.toLowerCase().indexOf("<user_num>");
index += "<user_num>".length();
int index2 = input.toLowerCase().indexOf("</user_num>");
userNum = Integer.parseInt(input.substring(index, index2));
}
}
} catch (IOException e) {
Log.e("TCPClient", "IOException while reading input stream");
listening = false;
}
}
}
});
this.listening = true;
this.listenThread.setDaemon(true);
this.listenThread.start();
} catch (UnknownHostException e) {
System.err.println("Don't know about host");
return false;
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection");
return false;
} catch (Exception e) {
System.err.println(e.getMessage().toString());
return false;
}
return true;
}
public void sendMessage(String msg) {
if(out != null)
{
out.println(msg);
out.flush();
}
}
public void disconnect() {
try {
if(out != null){
out.close();
out = null;
}
if(in != null){
in.close();
in = null;
}
if (socket != null) {
socket.close();
socket = null;
}
if(this.listenThread != null){
this.listening = false;
this.listenThread.interrupt();
}
this.userNum = -1;
} catch (IOException ioe) {
System.err.println("I/O error in closing connection.");
}
}
}
LASTLY, here is what I have been coding today and cannot seem to get this to work. I don't get any blatant exceptions, just a warning on Logcat, that says, "Couldn't get I/O for the connection".
public class AndroidClientCompnt extends Activity {
private TcpClient myTcpClient = null;
private UdpClient udpClient;
private static final String IP_ADDRESS_SHARED_PREFS = "ipAddressPref";
private static final String PORT_SHARED_PREFS = "portNumberPref";
private String encryptPassLoginActivity;
private String getIpAddressSharedPrefs;
private String getPassword, getName, getRegionSelect, getGridSelect;
private String fName, lName;
private SharedPreferences settings;
private boolean resultCheck = false;
private int portNum;
PVDCAndroidClient client;
private String name;
private CharSequence[] getView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.main);
Intent intent = getIntent();
// getting object's properties from LoginActivity class.
getName = intent.getStringExtra("name");
getPassword = intent.getStringExtra("password");
getRegionSelect = intent.getStringExtra("regionSelect");
getGridSelect = intent.getStringExtra("gridSelect");
Log.d("VARIABLES", "getName = " + getName + "getPassword" + getPassword
+ "getRegionSelect = " + getRegionSelect + ".");
setResult(Activity.RESULT_CANCELED);
client = new PVDCAndroidClient();
}
#Override
protected void onStart() {
super.onStart();
// Take care of getting user's login information:
// grid selected as well? sometime?
settings = PreferenceManager.getDefaultSharedPreferences(this);
getIpAddressSharedPrefs = settings.getString(IP_ADDRESS_SHARED_PREFS,
"");
portNum = Integer.parseInt(settings.getString(PORT_SHARED_PREFS, ""));
Log.d("SHARED" + getIpAddressSharedPrefs + "port " + portNum, "");
if (getIpAddressSharedPrefs.length() != 0 && portNum != 0) {
try {
// first connect attempt.
client.connect(getIpAddressSharedPrefs, portNum);
resultCheck = client.isConnected();
// here is where I want to call Async to do login
// or do whatever else.
UploadTask task = new UploadTask();
task.execute();
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "Could not connect.",
Toast.LENGTH_LONG).show();
e.printStackTrace();
}
} else {
Toast.makeText(getApplicationContext(),
"Ip preference and port blank", Toast.LENGTH_LONG).show();
}
finish();
}
private class UploadTask extends AsyncTask<String, Integer, Void> {
#Override
protected void onPreExecute() {
Toast.makeText(getApplicationContext(), "Loading...",
Toast.LENGTH_LONG).show();
}
#Override
protected Void doInBackground(String... names) {
// encrypting user's password with Md5Hash class.
try {
encryptPassLoginActivity = MdHashing
.MD5(getPassword.toString());
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (resultCheck == true) {
String[] firstAndLast;
String spcDelmt = " ";
firstAndLast = name.toString().split(spcDelmt);
fName = firstAndLast[0];
lName = firstAndLast[1];
// set up the tcp client to sent the information to the
// server.
client.login(fName, lName, encryptPassLoginActivity,
getRegionSelect, 128, 128, 20);
}
return null;
}
#Override
protected void onPostExecute(Void result) {
Intent goToInWorld = new Intent(
AndroidClientCompnt.this.getApplicationContext(),
PocketVDCActivity.class);
startActivity(goToInWorld);
Toast.makeText(getApplicationContext(), "Connected",
Toast.LENGTH_LONG).show();
}
}
}
I know this is a super long post and I am asking a lot but if anyone could take a look at this I would very much appreciate it. I've been at this all day, trying to make use of these helper classes I got and can't get it to work. It also doesn't help that I'm not too experienced in this client/server stuff. Any nudges in the right direction or an accepted solution would REALLY mean something to me.
Thank you kindly,
Have a good evening.
Can you post your manifest?
You may need to add the following :
<uses-permission android:name="android.permission.INTERNET"/>
Additionally - I assume you see nothing ever happen on the server side of this connection?
1) Make sure you have the following permission in your Android-Manifest file:
<uses-permission android:name="android.permission.INTERNET/>
w/o this you definitely won't be making any tcp/ip connections.
2) You will want to run the code in debug mode, and place breakpoints where the connection information
is set and also what results are at several points. In other words you need to dig deeper.
If you are somewhat new to coding there is no better investment of time than in running the debugger and stepping line by line through the code. Code only comes to life inside a debugger, where you can see the values of variables and results. So set several breakpoints, step through and you will see more. It is more difficult to debug where there are threads however.