socket-io on Android httpConnection memory leak - android

I'm using socket-io on android .
('com.github.nkzawa:socket.io-client:0.3.0')
While testing my app on Nexus 10 device (Android 4.2.1) i discovered that after calling mSocket.connect() a libcore.net.http.HttpConnection Object is created every 12.7 seconds or so by libcore.net.http.HttpConnectionPool. that causes "Too many open files error" and eventually the app freezes or crash .
Does not happen on (Android 4.4.2) Samsung GS5 device
It doesn't happens if i connect to a non SSL server (http vs https)
I'm connecting to a self signed certificate server - not sure if it's related to the leak .
calling socket disconnect does not free the HttpConnection objects
while investigating the leak i created an empty android project that reproduce the leak. Below i attached only the code that was added on top an empty "hello world" project.
note that on my original app - the connection to the server is successful.
onError callbacks are placed but not called. On the server side only one connection is made .Emitting and receiving Msgs is successful . Only when the HttpConnection Object count reaches to 300 or so, "too many open files" error occurs and causes various problems.
the fact that it happens only on some android versions,only on SSL connections, and that connect causes the leak but disconnect does not free it, really puzzles me.
-code
Added to build.gradle dependencies
compile 'com.github.nkzawa:socket.io-client:0.3.0'
Added to Android Manifest
<uses-permission android:name="android.permission.INTERNET" />
Main Activity....
import com.github.nkzawa.socketio.client.IO;
import com.github.nkzawa.socketio.client.Socket;
import java.net.URISyntaxException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
.....
mSocket.connect();
}
private TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[] {};
}
public void checkClientTrusted(X509Certificate[] chain,String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
} };
private Socket mSocket;
{
try
{
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, null);
IO.setDefaultSSLContext(sc);
HttpsURLConnection.setDefaultHostnameVerifier(new RelaxedHostNameVerifier());
mSocket = IO.socket("https://10.0.0.1");
mSocket.connect() ;
}
catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
catch (URISyntaxException e) {
e.printStackTrace();
}
}
public static class RelaxedHostNameVerifier implements HostnameVerifier {
public boolean verify(String hostname, SSLSession session) {
return true;
}
}

OK . got it .
The every 12.7 sec connection leak was the ping . changing the ping interval on my server helped a little.
but it turns out that httpConnection was leaked on every Msg sent to the server.
so basically it was not a solution.
After a little bit of digging i found this online.
http://android-developers.blogspot.co.il/2011/09/androids-http-clients.html
To summarize.
"Prior to Froyo, HttpURLConnection had some frustrating bugs. In particular, calling close() on a readable InputStream could poison the connection pool. Work around this by disabling connection pooling:"
private void disableConnectionReuseIfNecessary() {
// HTTP connection reuse which was buggy pre-froyo
if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) {
System.setProperty("http.keepAlive", "false");
}
}
As stated i'm suffering from this leak on Jelly bean not froyo. I removed the condition.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
System.setProperty("http.keepAlive", "false") ;
...
}

Related

SafetyNet.listHarmfulApps() does not run on emulator

While I have seen multiple posts and blogs that it doesn't work on the emulator, I've also seen blogs stating that we can do testing on emulators which are equipped with Google Play Services. We have such emulators and I've setup one such emulator ('Play Store enabled emulators)'). Is that the correct assumption? Can I test SafetyNet API integration with such an emulator?
It runs Android 8.1.
My code is as follows (ignore silly mistakes, the code compiles in my laptop. I've just edited some parts to maintain my company's confidentiality).
In this code, the following logs print into my logcat:- About to get harmful apps and Enabled app verification. But no other log statement from this class prints. Does anyone know why?
package some.kindof.package;
import android.content.Context;
import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.common.api.CommonStatusCodes;
import com.google.android.gms.safetynet.SafetyNetClient;
import com.google.android.gms.safetynet.SafetyNetStatusCodes;
import com.google.android.gms.safetynet.SafetyNetApi.HarmfulAppsResponse;
import com.google.android.gms.safetynet.SafetyNetApi;
import com.google.android.gms.safetynet.HarmfulAppsData;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnFailureListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HarmfulAppsDetector {
private static final Logger LOGGER = LoggerFactory.getLogger(HarmfulAppsDetector.class);
private HarmfulAppsResponseParser parser;
public boolean checkHarmfulApps(final SafetyNetClient safetyNetClient) throws Exception {
try {
LOGGER.info("About to get harmful apps"); //This prints
try {
safetyNetClient.enableVerifyApps();
} catch (Throwable e) {
LOGGER.error("Could not enable app verification");
System.exit(0); //Assume app will exit
}
LOGGER.info("Enabled app verification"); //This prints
//Check that verify apps is enabled
try {
safetyNetClient
.isVerifyAppsEnabled()
.addOnCompleteListener(new OnCompleteListener<SafetyNetApi.VerifyAppsUserResponse>() {
#Override
public void onComplete(Task<SafetyNetApi.VerifyAppsUserResponse> task) {
LOGGER.info("Verified that app verification is enabled or not? See right below:-");
LOGGER.info("See this:- " + task.getResult().isVerifyAppsEnabled());
}
});
} catch (Throwable e) {
LOGGER.error("Error checking whether app verification is enabled", e);
}
//List harmful apps using Google's SafetyNet APIs
safetyNetClient
.listHarmfulApps()
.addOnCompleteListener(new OnCompleteListener<HarmfulAppsResponse>() {
#Override
public void onComplete(Task<HarmfulAppsResponse> harmfulAppsResponseTask) {
LOGGER.info("Task is over.");
if (harmfulAppsResponseTask.isSuccessful()) {
LOGGER.info("Was able to hit Google and get response.");
HarmfulAppsResponse result = harmfulAppsResponseTask.getResult();
LOGGER.info("Response is:- " + result);
boolean harmfulAppsExist = parser.doHarmfulAppsExist(result);
if(harmfulAppsExist) {
//Blah do something here
}
} else {
LOGGER.error("An error occurred. " +
"Call isVerifyAppsEnabled() to ensure " +
"that the user has consented.");
}
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(Exception e) {
LOGGER.error("Task exception", e);
}
});
//Calling listHarmfulApps is now over
return true; //Just for testing, have to parse output and return that when the code actually works
} catch (Throwable e) {
LOGGER.error("Error occurred using Google for verifying harmful apps", e);
throw e;
}
}
}
Why do the async parts of the code, calls to isVerifyAppsEnabled() and listHarmfulApps(), not seem to even execute?

Android Java Sockets delay in sending data

UPDATE:
Thank you for the thoughts. I have debugged the issue I believe down to the connection between the android to the ESP8266. I believe there may be something going on with the ESP because when I connect the android to my pc it seems to connect and work well. There are some very minor delays but nothing like when it is connected to the ESP. Therefore I am thinking the ESP is causing the delay. That being said I am not sure what could cause this. I have tried using the ESP8266 2.3.0 ver of the libraries in Arduino IDE 1.6.8 but can't seem to figure out why the delay. I did connect the android app to my internal router and then send to the PC with no issues. However it doesn't seem to work with the ESP. I can't believe I am the only one that is seeing this... If anyone else has this working please let me know how you did it. My eternal gratitude would be yours.
Here is the ESP Arduino code:
WiFiServer server(2390); // TCP/IP
SoftwareSerial mySerial( 4, 5); // RX, TX
void setup( )
{
Serial.begin( 115200 );
WiFi.mode(WIFI_STA);
WiFi.softAP( "mySSID", "myPASS");
server.begin();// START TCP/IP SERVER
}
WiFiClient client;
void loop( )
{
if (client)
{
while (client.connected())
{
if (client.available())
{
char command = client.read();
Serial.println(itoa(command,buffer,10));
}
}
}
else
{
client = server.available();
}
}
I am trying to get almost instantaneous communication using TCP/IP sockets between android (Java) and ESP8266. The problem I am seeing is a significant delay between when I press the button to when the android will actually send the data. It seems to sometimes send right when I tap the Go Button but after the first time it will not send for 5-10 seconds. When it is stuck I tap the Go button a number of times and after the delay they all seem to send at once or start sending in spurts. I look at the network monitor in Android Studio and the delay is noticable from the time I tap the button until the traffic shows up on the network panel in the Monitors tab.
I am using the Android Studio Debugger to test the code.
Is there something that I am not doing correctly? Or perhaps is there a better implementation for near instant communication between devices?
Thank you for your assistance in advance!
Android Device:
Samsung Note 4 - v5.1.1 Android v2.0
Android Studio
ESP Device:
ESP8266 using Arduino Studio 1.6.8
Here is my Code:
public class MainActivity extends AppCompatActivity
{
private Socket socket;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onClick(View view)
{
try
{
new AsyncTaskRunner().execute("");
}
catch (Exception e)
{
e.printStackTrace();
}
}
private class AsyncTaskRunner extends AsyncTask<String, String, String>
{
private String resp;
ProgressDialog progressDialog;
#Override
protected String doInBackground(String... params)
{
try
{
DataOutputStream dataOut;
Socket s = new Socket("192.168.4.1", 2390);
dataOut=new DataOutputStream(s.getOutputStream());
byte[] outputData = new byte[9];
outputData[0] = 1;
outputData[1] = 2;
outputData[2] = 3;
outputData[3] = 4;
outputData[4] = 5;
outputData[5] = 6;
outputData[6] = 7;
outputData[7] = 8;
outputData[8] = 9;
dataOut.write(outputData); // Red
dataOut.flush();
dataOut.close();
s.close();
}
catch (UnknownHostException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
return resp;
}
#Override
protected void onPostExecute(String result) {
}
#Override
protected void onProgressUpdate(String... text) {
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.jered.networktest.MainActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Go"
android:onClick="onClick"/>
</RelativeLayout>
I had this problem for the case while I wanted to transmit some data to an access point Esp8266-01. I think this delay occurred since if (client. available()) inside while (client.connected())loop waits to receive data until client is available. hence, makes a delay (it was exactly 5 seconds me). to avoid this unpleasant behavior, I appended a carriage return '\r' in write command of AsyncTask in the android MainActivity.java file then modified Arduino sketch to wait until the server receives a carriage return, I mean some code like this String request = client.readStringUntil('\r');
finally, two buttons as known as btn1 and btn2 in the android app send two strings /led/on and /led/off respectively. by now ESP8266 receives carriage return and flush client immediately then there is no delay to execute other section of the program.
the following program turns one led on or off (GPIO 0 pin of the ESP8266-01) according to the pressed button in Android app. but don't forget to set ground GPIO 0 of ESP8266-01 just while programming it and don't forget to connect mobile wifi to ESP wifi network first but you can use wifi configuration to connect to ESP wifi automatically too (see this link).
Arduino code:
#include<ESP8266WiFi.h>
// WiFi Definitions
const char* ssid = "Esp8266TestNet";
const char* password = "Esp8266Test"; // has to be longer than 7 chars
const char* value = "";
int ledPin = 0; // GPIO 0
WiFiServer server(80);
void setup() {
Serial.begin(115200);
delay(10);
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, HIGH); // turn on
WiFi.mode(WIFI_AP);
WiFi.softAP(ssid, password, 1, false);
server.begin();
}
void loop() {
// Check of client has connected
WiFiClient client = server.available();
if(!client) {
return;
}
// Read the request line
String request = client.readStringUntil('\r');
Serial.println(request);
client.flush();
// Match request
if(request.indexOf("/led/on") != -1) {
digitalWrite(ledPin, HIGH);
value = "on";
} else if (request.indexOf("/led/off") != -1) {
digitalWrite(ledPin, LOW);
value = "off";
}
else {
Serial.println("not validate");
}
client.flush();
// JSON response
String s = "HTTP/1.1 200 OK\r\n";
s += "Content-Type: application/json\r\n\r\n";
s += "{\"data\":{\"message\":\"success\",\"value\":\"";
s += value;
s += "\"}}\r\n";
s += "\n";
// Send the response to the client
client.print(s);
delay(1);
Serial.println("Client disconnected");
// The client will actually be disconnected when the function returns and the client object is destroyed
}
manifest XML:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myhgrtest">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/btn1"
android:text="btn1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
></Button>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/btn2"
android:text="btn2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
></Button>
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.java:
package com.example.myhgrtest;
import androidx.appcompat.app.AppCompatActivity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.Socket;
import java.net.URL;
public class MainActivity extends AppCompatActivity {
Button btn1,btn2;
TcpClient mTcpClient;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn1=findViewById(R.id.btn1);
btn2=findViewById(R.id.btn2);
btn1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
send_request1();
}
});
btn2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
send_request2();
}
});
}
public class ConnectTask extends AsyncTask<String, String, TcpClient> {
#Override
protected TcpClient doInBackground(String... message) {
//we create a TCPClient object
mTcpClient = new TcpClient(new TcpClient.OnMessageReceived() {
#Override
//here the messageReceived method is implemented
public void messageReceived(String message) {
//this method calls the onProgressUpdate
publishProgress(message);
}
});
mTcpClient.run();
return null;
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
//response received from server
Log.d("test", "response " + values[0]);
//process server response here....
}
}
public void send_request1() {
send_request1 sr = new send_request1();
sr.execute();
}
public void send_request2() {
send_request2 sr = new send_request2();
sr.execute();
}
class send_request1 extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... voids) {
try { /*note : ip address must be in Quotation mark*/
/*note : port doesn't need to be inside the Quotation mark*/
Socket s = new Socket(/*ip address :*/"192.168.4.1",/*port :*/ 80);
PrintWriter printWriter = new PrintWriter(s.getOutputStream());
printWriter.write("/led/on"+"\r");
printWriter.flush();
printWriter.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
public void onPostExecute(final String Data) {
/*Data is what you receive from your server*/
Log.e("my_Data","Data is : " + Data);
}
}
class send_request2 extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... voids) {
try {
/*note : ip address must be in Quotation mark*/
/*note : port doesn't need to be inside the Quotation mark*/
Socket s = new Socket(/*ip address :*/"192.168.4.1",/*port :*/ 80);
PrintWriter printWriter = new PrintWriter(s.getOutputStream());
printWriter.write("/led/off"+"\r");
printWriter.flush();
printWriter.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
public void onPostExecute(final String Data) {
/*Data is what you receive from your server*/
Log.e("my_Data","Data is : " + Data);
//Toast.makeText(MainActivity.this, Data, Toast.LENGTH_SHORT).show();
}
}
}
I don't think anyone can say for certain where the problem lays.
To prevent you (and others) from chasing ghosts, you really want to split up your problem:
Make sure your 'doInBackground' isn't delayed, e.g. by logging to the android logging system, console, debugger, or doing something easy in the ui.
Make sure sending on the Android side isn't delayed, by writing a tiny listener in e.g. Java, and running that on your PC.
Make sure listening isn't delayed, by creating a tiny sender in Java, and running that on your PC.
This way divide your problem till you find the root cause :)

Reading gmail inbox with android 4.2 up

I am trying to get the gmail inbox using javamail with this code:
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import com.sun.mail.imap.IMAPFolder;
import com.sun.mail.imap.IMAPStore;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import java.util.Properties;
public class HomeActivity extends Activity {
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button emailRead=(Button)findViewById(R.id.button);
emailRead.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Runnable r=new Runnable() {
#Override
public void run() {
Properties props = new Properties();
props.setProperty("mail.store.protocol", "imaps");
Session session = Session.getDefaultInstance(props, null);
IMAPStore imapStore = null;
try {
imapStore = (IMAPStore) session.getStore("imaps");
imapStore.connect("imap.gmail.com", "myemail#gmail.com", "mypassword");
final IMAPFolder folder = (IMAPFolder) imapStore.getFolder("Inbox");
folder.open(IMAPFolder.READ_WRITE);
Message m[]=folder.getMessages();
for(Message n:m){
System.out.println(n.getSubject());
}
} catch (MessagingException e) {
e.printStackTrace();
}
}
};
Thread t=new Thread(r);
t.start();
}
});
}
}
It works in emulator, but when run on a real device(with working internet connection) I constantly fail and get the exception:
com.sun.mail.util.MailConnectException: Couldn't connect to host, port: imap.gmail.com, 993; timeout -1;
nested exception is:
java.net.SocketTimeoutException: failed to connect to imap.gmail.com/2607:f8b0:400e:c02::6c (port 993) after 90000ms
Why am I receiving an MailConnectException, and how can I fix it?
EDIT:
Here are the links I have tried, but with the same result:
1)Reading Gmail mails using android SDK
2)Are there any good short code examples that simply read a new gmail message?
3)Reading all new messages from my gmail using javamail
Its just the subset of what I have tried before posting. I request someone to please share a live working code, which works on a real device here.
EDIT2:
I have tested this on three real devices. One was using wifi internet.Two others were using Gprs for net connectivity. So it appears that gmail setting for javamail have changed with android. The javamail code is working for me on desktop java.But seems something strange with android real devices.
U are not allowed to use networking in main UI thread from android 3.0 and up.
So setup aSyncTask to solve your problem

android: communication with PC desktop app and remote mediaplayer controller

Dont get angry on me please. I have two questions, I think on very similar theme, so I decided to merge them into one. I have my app on android that is using sensors to do some calculations. I am storing there sesults in my database. What i want to do is to send my data from my phone to my desktop app also with a database (on button click).
To be more precise, here is an example: My light sensor reads current light intensity. Lets say it is 1000lux. Now, when I click my button "Send" in my android app, it will send this value to my desktop apps database. That desktop app will read that value and will show it to user.
Is it possible via WIFI? or better via web, so i will not be limited with distance?
How can android manage this kind of communication?
And my second question is, if controlling media player on my PC is similar to what i said.
EDIT:
I did some research and found one Socket tutorial. I tried it exactly like it is there. So i have this in my android app:
public class Client extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_client);
Client myCli = new Client();
try {
myCli.run();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_client, menu);
return true;
}
public void run() throws Exception {
Socket mySkt = new Socket("192.168.1.6", 9999);
PrintStream myPS = new PrintStream(mySkt.getOutputStream());
myPS.println("Hello server");
BufferedReader myBR = new BufferedReader
(new InputStreamReader(mySkt.getInputStream()));
}
}
and this in netBeans:
//Author: WarLordTech
//Website: http://www.youtube.com/user/WarLordTech
import java.io.*;
import java.net.*;
public class Server {
public static void main(String[] args) throws Exception{
Server myServ = new Server();
myServ.run();
}
public void run() throws Exception{
ServerSocket mySS = new ServerSocket(9999);
Socket SS_accept = mySS.accept();
BufferedReader SS_BF= new BufferedReader(new InputStreamReader
(SS_accept.getInputStream()));
String temp = SS_BF.readLine();
System.out.println(temp);
if (temp!=null) {
PrintStream SSPS = new PrintStream(SS_accept.getOutputStream());
SSPS.println("Got something");
}
}
}
It still isnt workiong. Do I have to set up my network somehow?
You could do it using TCP Sockets. Many languages have implementations for Socket programming so you would "need" to program your desktop app in Java (of course that is always possible!).
Socket Tutorial in Java
This would work over the net and local wifi. You could use other methods for local wifi such as a UDP connection. You'd need to setup a TCP server and make sure you had access etc.
There may be other ways to do this but it's not such a trivial task to do!

Activity terminating abruptly without any exception

I have an Activity that sometimes terminates abruptly but without any exception being reported or logged. The Activity just ends suddenly and the app returns to the previous Activity in the stack.
I'm using ACRA (http://code.google.com/p/acra/) to capture and report errors, and it works well for all other errors in the app, but in this one case it does not detect any exception having been thrown. Nor is anything reported in Logcat.
It always happens at the same "place" in the app, when the user takes a certain action, but it is very intermittent and I've yet to make it happen while attached with the debugger.
Are there any other options (besides ACRA and Logcat) for determining what is happening to the Activity? Or is this something in the world of Android Activities that is "known?"
If it matters, this Activity is doing Bitmap manipulation and saving; I've had to take steps to avoid potential out of memory errors; but I was getting ACRA reports of OOM exceptions when they did occur, so I don't think this is due to OOME.
At the point where it seems to fail, the Activity creates an AsyncTask and executes it. Here's the code for the AsyncTask (ActivityAsyncTask is a really simple super class; EditPhotoEctivity is the one that is dying without an exception, sometime during the creation or execution of this task):
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.media.MediaScannerConnection;
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
import android.net.Uri;
import android.view.View;
public class CompositeAndSavePictureTask extends ActivityAsyncTask<File, Void, Uri>
implements MediaScannerConnectionClient {
public static final String FILE_EXTENSION = ".jpg";
private static final int COMPRESSION_QUALITY = 100;
private File file;
private Uri mSavedImageUri;
private MediaScannerConnection mMediaScannerConnection;
public CompositeAndSavePictureTask(EditPhotoActivity owningActivity) {
super(owningActivity);
mMediaScannerConnection = new MediaScannerConnection(owningActivity, this);
}
#Override
protected EditPhotoActivity getOwner() {
return (EditPhotoActivity) super.getOwner();
}
#Override
protected void onPreExecute() {
getOwner().toggleControlsVisibility(false);
}
#Override
protected Uri doInBackground(File... params) {
file = params[0];
Bitmap picture = null;
View mainContentView = getMainContentView();
try {
picture = captureBitmap(mainContentView);
saveBitmap(picture);
} catch (Exception ex) {
LogUtils.logError(this, "Could not save photo", ex);
setError(ex);
return null;
} finally {
cleanUpCapture(mainContentView, picture);
}
try {
mMediaScannerConnection.connect();
synchronized (mMediaScannerConnection) {
mMediaScannerConnection.wait();
}
} catch (InterruptedException ex) {
LogUtils.logInfo(this, "MediaScannerConnection was interrupted during scan.");
setError(ex);
}
return mSavedImageUri;
}
protected Bitmap captureBitmap(View mainContentView) throws Exception {
mainContentView.setDrawingCacheEnabled(true);
return mainContentView.getDrawingCache();
}
protected void cleanUpCapture(View mainContentView, Bitmap capturedBitmap) {
mainContentView.setDrawingCacheEnabled(false);
if (capturedBitmap != null) {
capturedBitmap.recycle();
}
}
protected void saveBitmap(Bitmap bitmap) throws IOException {
BufferedOutputStream outStream = null;
try {
outStream = new BufferedOutputStream(FileUtils.openOutputStream(file));
bitmap.compress(CompressFormat.JPEG, COMPRESSION_QUALITY, outStream);
} finally {
try {
if (outStream != null) {
outStream.close();
}
} catch (IOException ex) {
LogUtils.logError(this, "Could not close output stream", ex);
}
}
}
#Override
protected void onPostExecute(Uri savedFileURI) {
getOwner().toggleControlsVisibility(true);
getOwner().onSaveResult(savedFileURI);
}
public void onMediaScannerConnected() {
mMediaScannerConnection.scanFile(file.getPath(), null /* mimeType */);
}
public void onScanCompleted(String path, Uri uri) {
mMediaScannerConnection.disconnect();
mSavedImageUri = uri;
synchronized (mMediaScannerConnection) {
mMediaScannerConnection.notify();
}
}
}
See also view.getDrawingCache() only works once, which has some relation but is a slightly different scenario.
Any and all ideas are welcomed.
I had a similar problem before. I was trying to open a file for reading, but instead of typing the complete address which was "/sdcard/something.txt", I gave it the wrong path (just "something.txt") without the sdcard part. After a lot of pain I have discovered that if you want the program to open something that is not really there, the activity just ends whitout any notice (to to console, to logcat etc. ). As it won't send back an error, it won't go on the "catch" branch.
So, I would suggest checking the file opperations.
Disclaimer: I know for sure that this causes this kind of behavior when trying to open the wrong path using the ndk and native code, but I suppose it would be the same if you do this mistake from in java code.
Please forgive the newbie comment, but if it's terminating without a Exception, you may be catching it somewhere and the program is continuing on it's merry way, but in an invalid state.

Categories

Resources