I am using airbrake to catch crash reports
As soon as the app crashes I can see the report on the dashboard, but there is no alert in my app to ask the user to "Send Error Report". How can I enable airbrake alerts to ask the user to send the report for the crash. Could not find anything related to this on airbrake documentation. Thanks.
Reading the AirbrakeNotifier code you linked to reveals that it automatically sends crashes as soon as possible.
You would have to modify this class to ask the user whether to send crashes, e.g. the next time you initialise the Airbrake class.
For example, HockeyApp has an option to do this in its CrashManager class.
Though I prefer to always automatically send crash reports to the server; there's usually no reason to bother users with this request.
If you want to send crash report to be send you can make class to handle UnCaughtException that will handle all crash exception. You can write code like this:
import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.Date;
import java.util.Locale;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Environment;
import android.os.Looper;
import android.os.StatFs;
import android.util.Log;
public class UnCaughtException implements UncaughtExceptionHandler {
private Context context;
private static Context context1;
public UnCaughtException(Context ctx) {
context = ctx;
context1 = ctx;
}
private StatFs getStatFs() {
File path = Environment.getDataDirectory();
return new StatFs(path.getPath());
}
private long getAvailableInternalMemorySize(StatFs stat) {
long blockSize = stat.getBlockSize();
long availableBlocks = stat.getAvailableBlocks();
return availableBlocks * blockSize;
}
private long getTotalInternalMemorySize(StatFs stat) {
long blockSize = stat.getBlockSize();
long totalBlocks = stat.getBlockCount();
return totalBlocks * blockSize;
}
private void addInformation(StringBuilder message) {
message.append("Locale: ").append(Locale.getDefault()).append('\n');
try {
PackageManager pm = context.getPackageManager();
PackageInfo pi;
pi = pm.getPackageInfo(context.getPackageName(), 0);
message.append("Version: ").append(pi.versionName).append('\n');
message.append("Package: ").append(pi.packageName).append('\n');
} catch (Exception e) {
Log.e("CustomExceptionHandler", "Error", e);
message.append("Could not get Version information for ").append(
context.getPackageName());
}
message.append("Phone Model: ").append(android.os.Build.MODEL)
.append('\n');
message.append("Android Version: ")
.append(android.os.Build.VERSION.RELEASE).append('\n');
message.append("Board: ").append(android.os.Build.BOARD).append('\n');
message.append("Brand: ").append(android.os.Build.BRAND).append('\n');
message.append("Device: ").append(android.os.Build.DEVICE).append('\n');
message.append("Host: ").append(android.os.Build.HOST).append('\n');
message.append("ID: ").append(android.os.Build.ID).append('\n');
message.append("Model: ").append(android.os.Build.MODEL).append('\n');
message.append("Product: ").append(android.os.Build.PRODUCT)
.append('\n');
message.append("Type: ").append(android.os.Build.TYPE).append('\n');
StatFs stat = getStatFs();
message.append("Total Internal memory: ")
.append(getTotalInternalMemorySize(stat)).append('\n');
message.append("Available Internal memory: ")
.append(getAvailableInternalMemorySize(stat)).append('\n');
}
public void uncaughtException(Thread t, Throwable e) {
try {
StringBuilder report = new StringBuilder();
Date curDate = new Date();
report.append("Error Report collected on : ")
.append(curDate.toString()).append('\n').append('\n');
report.append("Informations :").append('\n');
addInformation(report);
report.append('\n').append('\n');
report.append("Stack:\n");
final Writer result = new StringWriter();
final PrintWriter printWriter = new PrintWriter(result);
e.printStackTrace(printWriter);
report.append(result.toString());
printWriter.close();
report.append('\n');
report.append("**** End of current Report ***");
Log.e(UnCaughtException.class.getName(),
"Error while sendErrorMail" + report);
sendErrorMail(report);
} catch (Throwable ignore) {
Log.e(UnCaughtException.class.getName(),
"Error while sending error e-mail", ignore);
}
}
/**
* This method for call alert dialog when application crashed!
*/
public void sendErrorMail(final StringBuilder errorContent) {
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
new Thread() {
#Override
public void run() {
Looper.prepare();
builder.setTitle("Sorry...!");
builder.create();
builder.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog,
int which) {
System.exit(0);
}
});
builder.setPositiveButton("Report",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog,
int which) {
Intent sendIntent = new Intent(
Intent.ACTION_SEND);
String subject = "Your App crashed! Fix it!";
StringBuilder body = new StringBuilder("Yoddle");
body.append('\n').append('\n');
body.append(errorContent).append('\n')
.append('\n');
// sendIntent.setType("text/plain");
sendIntent.setType("message/rfc822");
sendIntent
.putExtra(
Intent.EXTRA_EMAIL,
new String[] { "your_email#domain.com" });
sendIntent.putExtra(Intent.EXTRA_TEXT,
body.toString());
sendIntent.putExtra(Intent.EXTRA_SUBJECT,
subject);
sendIntent.setType("message/rfc822");
context1.startActivity(sendIntent);
System.exit(0);
}
});
builder.setMessage("Oops,Your application has crashed.");
builder.show();
Looper.loop();
}
}.start();
}
}
And declare this exception class in every Class file to get log of each crash. Following code you can use to add in Activity or any other class:
Thread.setDefaultUncaughtExceptionHandler(new UnCaughtException(
YourActivity.this));
Related
I wrote an Android app. Export as signed APK sent via mail installed to device.- not at Market.
At runtime it will save they data to internal storage with similar code:
FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(string.getBytes());
fos.close();
As I know - correct me if I am wrong - it is saved to /data/data/com.mycompany.myapp/FILENAME
Because it is saved with MODE_PRIVATE I am not sure if any other app from Market or mine can see it save it. Maybe if I create an app with the same signature?
The phone it is not rooted. I have tryed many backup, copy with app and ADB shell.
App didn't saved my file, adb shell gave permission denied.
Is there any solution with programming or not to get that file?
I wrote a little code part to test it:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
private EditText tfData;
private Button btSave, btLoad;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tfData = (EditText) findViewById(R.id.tfData);
btSave = (Button) findViewById(R.id.btSave);
btLoad = (Button) findViewById(R.id.btLoad);
btSave.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
doSave();
}
});
btLoad.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
doLoad();
}
});
tfData.setText("Some secret data");
boolean btLoadVisible = false; // TODO change this value for the second build!
if (!btLoadVisible) {
btLoad.setVisibility(View.GONE);
}
else{
btSave.setVisibility(View.INVISIBLE);
}
}
private static final String FILENAME = "private.dat";
private void doSave() {
String text = null;
if (tfData.getText() == null) {
Toast.makeText(this, "Please enter a string!", Toast.LENGTH_SHORT).show();
return;
}
text = tfData.getText().toString();
if (text == null || text.length() == 0) {
Toast.makeText(this, "Please enter a string!!!", Toast.LENGTH_SHORT).show();
}
FileOutputStream fos = null;
try {
fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(text.getBytes("UTF-8"));
fos.close();
fos = null;
new AlertDialog.Builder(this).setTitle("Saved").setMessage("Your data is saved:\n" + text+"\nChange the build to recover it!")
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
}).show();
} catch (Exception e) {
Log.e("doSave", "Can't save ...", e);
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
// I don't care:
e.printStackTrace();
}
}
}
}
private void doLoad() {
FileInputStream fis = null;
try {
fis = openFileInput(FILENAME);
} catch (FileNotFoundException e) {
e.printStackTrace();
new AlertDialog.Builder(this)
.setTitle("FileNotFoundException")
.setMessage(
"The file with data can't be found. Or it wasn't saved at all or you have uninstalled the old app or... who knows.\nI can't recover the data, it is lost permanenty!!!")
.setPositiveButton("I am sad", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
}).show();
return; // I don't like return from catch...
}
if (fis != null) {
try {
int size = fis.available();// not the best, but now I hope is possible to read 10-30 bytes without blocking
byte[] buff = new byte[size];
int readCount = fis.read(buff);
if (readCount != size) {
Toast.makeText(this, "Dammit can't read : " + size + " bytes, only " + readCount + ". Restart app, than phone? ", Toast.LENGTH_SHORT)
.show();
}
String text = new String(buff, "UTF-8");
tfData.setText(text);
new AlertDialog.Builder(this).setTitle("Loaded").setMessage("Your data is recovered:\n" + text)
.setPositiveButton("I am happy", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
}).show();
} catch (IOException e) {
Log.e("doLoad", "Can't load ...", e);
new AlertDialog.Builder(this).setTitle("IOException").setMessage("There is some error while reading the data:\n" + e.getMessage())
.setPositiveButton("I am sad", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
}).show();
}
}
}
}
Clean, build, export as signed apk: eg InternalMemoryReader_save.apk
save the keystore!!!
change the boolean btLoadVisible = false to boolean btLoadVisible = true .
export apk WITH THE SAME KEYSTORE! but diff name, eg InternalMemoryReader_load.apk - but can be a _datasaver _factoryservice whatever. This usually it is not given to the user.
Install the first apk and do a save.
do not uninstall the apk
lets propose you are blaming of data loss, can't open it ...and once in a mail you will receive the _load.apk from the support service. Install it without remove the old apk. It has the same package name, same signature, just diff file name.
I was able to load the data. It can be send via mail or processed there, the hardest part is done.
Conclusion:
If you are the app developer and if you have the keystore and able to sign a modified apk than you will have access to that internal, private file.
I hope I am helping somebody else to to recover his app data and not waste so much time.
If you know better solution, please let me know!
How can I show notification that shows when the application crashed (or service crashed), and if the user click on it, it send the StackTrace by email?
I saw some applications that do that.
Make your own class by extending the interface UncaughtExceptionHandler
public class UnCaughtException implements UncaughtExceptionHandler
{
private Context context;
private static Context context1;
public UnCaughtException(Context ctx)
{
context = ctx;
context1 = ctx;
}
private StatFs getStatFs()
{
File path = Environment.getDataDirectory();
return new StatFs(path.getPath());
}
private long getAvailableInternalMemorySize(StatFs stat)
{
long blockSize = stat.getBlockSize();
long availableBlocks = stat.getAvailableBlocks();
return availableBlocks * blockSize;
}
private long getTotalInternalMemorySize(StatFs stat)
{
long blockSize = stat.getBlockSize();
long totalBlocks = stat.getBlockCount();
return totalBlocks * blockSize;
}
private void addInformation(StringBuilder message)
{
message.append("Locale: ").append(Locale.getDefault()).append('\n');
try
{
PackageManager pm = context.getPackageManager();
PackageInfo pi;
pi = pm.getPackageInfo(context.getPackageName(), 0);
message.append("Version: ").append(pi.versionName).append('\n');
message.append("Package: ").append(pi.packageName).append('\n');
}
catch ( Exception e )
{
Log.e("CustomExceptionHandler", "Error", e);
message.append("Could not get Version information for ").append(context.getPackageName());
}
message.append("Phone Model: ").append(android.os.Build.MODEL).append('\n');
message.append("Android Version: ").append(android.os.Build.VERSION.RELEASE).append('\n');
message.append("Board: ").append(android.os.Build.BOARD).append('\n');
message.append("Brand: ").append(android.os.Build.BRAND).append('\n');
message.append("Device: ").append(android.os.Build.DEVICE).append('\n');
message.append("Host: ").append(android.os.Build.HOST).append('\n');
message.append("ID: ").append(android.os.Build.ID).append('\n');
message.append("Model: ").append(android.os.Build.MODEL).append('\n');
message.append("Product: ").append(android.os.Build.PRODUCT).append('\n');
message.append("Type: ").append(android.os.Build.TYPE).append('\n');
StatFs stat = getStatFs();
message.append("Total Internal memory: ").append(getTotalInternalMemorySize(stat)).append('\n');
message.append("Available Internal memory: ").append(getAvailableInternalMemorySize(stat)).append('\n');
}
#Override
public void uncaughtException(Thread t, Throwable e)
{
try
{
StringBuilder report = new StringBuilder();
Date curDate = new Date();
report.append("Error Report collected on : ").append(curDate.toString()).append('\n').append('\n');
report.append("Informations :").append('\n');
addInformation(report);
report.append('\n').append('\n');
report.append("Stack:\n");
final Writer result = new StringWriter();
final PrintWriter printWriter = new PrintWriter(result);
e.printStackTrace(printWriter);
report.append(result.toString());
printWriter.close();
report.append('\n');
report.append("**** End of current Report ***");
Log.e(UnCaughtException.class.getName(), "Error while sendErrorMail" + report);
sendErrorMail(report);
}
catch ( Throwable ignore )
{
Log.e(UnCaughtException.class.getName(), "Error while sending error e-mail", ignore);
}
}
/**
* This method for call alert dialog when application crashed!
*/
public void sendErrorMail(final StringBuilder errorContent)
{
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
new Thread()
{
#Override
public void run()
{
Looper.prepare();
builder.setTitle("Sorry...!");
builder.create();
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener()
{
#Override
public void onClick(DialogInterface dialog, int which)
{
System.exit(0);
}
});
builder.setPositiveButton("Report", new DialogInterface.OnClickListener()
{
#Override
public void onClick(DialogInterface dialog, int which)
{
Intent sendIntent = new Intent(Intent.ACTION_SEND);
String subject = "Your App crashed! Fix it!";
StringBuilder body = new StringBuilder("Yoddle");
body.append('\n').append('\n');
body.append(errorContent).append('\n').append('\n');
// sendIntent.setType("text/plain");
sendIntent.setType("message/rfc822");
sendIntent.putExtra(Intent.EXTRA_EMAIL, new String[] { "yourmail#domain.com" });
sendIntent.putExtra(Intent.EXTRA_TEXT, body.toString());
sendIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
sendIntent.setType("message/rfc822");
context1.startActivity(sendIntent);
System.exit(0);
}
});
builder.setMessage("Oops,Your application has crashed");
builder.show();
Looper.loop();
}
}.start();
}
}
Set the CustomExceptionHandler as the DefaultExceptionHandler in your MainActivity
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
public class MainActivity extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Thread.setDefaultUncaughtExceptionHandler(new UnCaughtException(MainActivity.this));
int y = 5 / 0;
}
}
Note :
The above example code sends a email with the crash data. You can modify it to meet your need.
you can use ACRA library. From the doc
Acra catches exceptions, retrieves lots of context data and send them
to a Google Spreadsheet... or whatever backend you prefer.
or Crittercism. It supports
Error Monitoring
App Monitoring
I am using the following code to make the android device a ftp server (Android Internal storage). I am getting the exception of os.android.NetworkOnMainThread. I have tried to put the onStart code in the AsyncTask but app never executes and crashes on launch. Any help regarding the ftp server on Android will be great as i have no idea how to get it working.
Here is the MainActivity Code
package com.googlecode.simpleftp;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;
public class FTPServer extends Activity {
private static int COMMAND_PORT = 2121;
static final int DIALOG_ALERT_ID = 0;
private static ExecutorService executor = Executors.newCachedThreadPool();
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.my_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.new_game:
System.out.println("New game button is pressed!");
//newGame();
return true;
case R.id.quit:
System.out.println("Quit button is pressed!");
showDialog(DIALOG_ALERT_ID);
return true;
default:
return super.onOptionsItemSelected(item); }
}
#Override
protected Dialog onCreateDialog(int id){
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Are you sure you want to exit?")
.setCancelable(false).setPositiveButton("yes", new DialogInterface.OnClickListener(){
#Override
public void onClick(DialogInterface dialog, int id){
FTPServer.this.finish();
}
})
.setNegativeButton("No", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
AlertDialog alert = builder.create();
return alert;
}
HEre is the ServerPI Code
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class ServerPI implements Runnable{
private Socket clientSocket;
private BufferedReader in;
private PrintWriter out;
private String baseDir;
private String relativeDir;
private String absoluteDir;
private String fileName;
private String filePath;
public ServerPI(Socket incoming) throws IOException{
this.clientSocket = incoming;
in = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
out = new PrintWriter(this.clientSocket.getOutputStream(), true);
baseDir = new File("").getAbsolutePath();
relativeDir = "/";
absoluteDir = baseDir + relativeDir;
fileName = "";
filePath = absoluteDir + "/" + fileName;
}
private void readCommandLoop() throws IOException {
String line = null;
reply(220, "Welcome to the SimpleFTP server!");
while((line = in.readLine()) != null){
int replyCode = executeCommand(line.trim());
if(replyCode == 221){
return;
}
}
}
private int executeCommand(String trim) {
// TODO Auto-generated method stub
return 0;
}
public int reply(int statusCode, String statusMessage){
out.println(statusCode + " " + statusMessage);
return statusCode;
}
#Override
public void run(){
try{
this.readCommandLoop();
} catch (IOException e){
e.printStackTrace();
}
finally {
try {
if(in != null){
in.close();
in = null;
}
if(out != null){
out.close();
out = null;
}
if (clientSocket != null){
clientSocket.close();
clientSocket = null;
}
}
catch (IOException e){
e.printStackTrace();
}
}
}
}
I have put the code in the AsyncTask, here it is
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
ServerSocket s = null;
Socket incoming = null;
try{
s = new ServerSocket(COMMAND_PORT);
String ip = (s.getInetAddress()).getHostAddress();
Context context = this.getApplicationContext();
CharSequence text = ip;
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, text, duration);
Thread.sleep(1000);
toast.show();
while(true){
incoming = s.accept();
executor.execute(new ServerPI(incoming));
}
}
catch(Exception e){
System.out.println(e.toString());
e.printStackTrace();
}
finally{
try
{
if(incoming != null)incoming.close();
}
catch(IOException ignore)
{
//ignore
}
try
{
if (s!= null)
{
s.close();
}
}
catch(IOException ignore)
{
//ignore
}
}
return "Executed";
}
#Override
protected void onPostExecute(String result) {
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(Void... values) {
}
}
Iam calling the longOpertation in onCreate method. What is the problem that the app crashes on launch.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fullscreen);
new LongOperation().execute();
}
Maybe because you didn't set up the permissions in the manifest? You've to set permission for internet usage.
If this doesn't work, please tell us which line is it throwing the exception.
while(true){ incoming = s.accept(); ...} You cannot put that in OnStart(). That should be done in a thread. So ServerSocket s = null; should be a variable of you activity.
So I went with Swiftp application (open source) as a service in my application which helped me to achieve my task. Thanks everyone who stepped forward to help. Here is the link if someone wants to follow
Please post your code here.
NetworkOnMainthreadException occurs because you maybe running Network related operation on the Main UI Thread. You should use asynctask for this purpose
This is only thrown for applications targeting the Honeycomb SDK or higher. Applications targeting earlier SDK versions are allowed to do networking on their main event loop threads, but it's heavily discouraged.
http://developer.android.com/reference/android/os/NetworkOnMainThreadException.html
class TheTask extends AsyncTask<Void,Void,Void>
{
protected void onPreExecute()
{ super.onPreExecute();
//display progressdialog.
}
protected void doInBackground(Void ...params)//return result here
{
//http request. do not update ui here
//call webservice
//return result here
return null;
}
protected void onPostExecute(Void result)//result of doInBackground is passed a parameter
{
super.onPostExecute(result);
//dismiss progressdialog.
//update ui using the result returned form doInbackground()
}
}
http://developer.android.com/reference/android/os/AsyncTask.html. Check the topic under the heading The 4 Steps.
A working example of asynctask # To use the tutorial in android 4.0.3 if had to work with AsynxTasc but i still dont work?.
The above makes a webserive call in doInBakckground(). Returns result and updates the ui by setting the result in textview in onPostExecute().
You can not do network operation in main thread in android 3.0 higher. Use AsyncTask for this network operation. See this for further explanation
Does anybody know how to modify the style of the "force close" window (FC dialog)?
I found a custom ROM with a nice picture at the dialog. At what place can I find the popup?
Try to override uncaughtException,
#Override
public void uncaughtException(Thread thread, Throwable e) {
e.printStackTrace();
try {
// create your custom dialog
displayErrorMessageToast();
Thread.sleep(3500);
} catch (Exception e1) {
Log.e(TAG, "Error: ", e1);
}
finally
{
killApplicationProcess(e);
}
}
for more info:
https://groups.google.com/forum/?fromgroups=#!topic/android-developers/2iUH1Knz8gw
Try the approach given in this blog
Copying here for quick reference:
Android UncaughtExceptionHandler
Implemented by objects that want to handle cases where a thread is being terminated by an uncaught exception. Upon such termination, the handler is notified of the terminating thread and causal exception. If there is no explicit handler set then the thread's group is the default handler.
Below i wrote the code user can send some bug report to Developer when application crashed.
Activity Code
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.ViewFlipper;
/**
*
* #author vijayakumar
*
*/
public class AndroidMADQAActivity extends Activity {
ViewFlipper flipper;
TextView textView = null;
Throwable throwable;
UnCaughtException un = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Thread.setDefaultUncaughtExceptionHandler(new UnCaughtException(AndroidMADQAActivity.this));
Integer[] items = { R.drawable.a, R.drawable.e,R.drawable.d,R.drawable.c};
setContentView(R.layout.main);
textView.setText("Helloo Error Welcome");
}
}
UnCaughtException.java
package com.madqa;
import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.Date;
import java.util.Locale;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Environment;
import android.os.Looper;
import android.os.StatFs;
import android.util.Log;
/**
* {#link UncaughtExceptionHandler} send an e-mail with
* some debug information to the developer.
*
* #author VIJAYAKUMAR
*/
public class UnCaughtException implements UncaughtExceptionHandler {
private static final String RECIPIENT = "iamvijayakumar#gmail.com";
private Thread.UncaughtExceptionHandler previousHandler;
private Context context;
private static Context context1;
public UnCaughtException(Context ctx) {
context = ctx;
context1 = ctx;
}
private StatFs getStatFs() {
File path = Environment.getDataDirectory();
return new StatFs(path.getPath());
}
private long getAvailableInternalMemorySize(StatFs stat) {
long blockSize = stat.getBlockSize();
long availableBlocks = stat.getAvailableBlocks();
return availableBlocks * blockSize;
}
private long getTotalInternalMemorySize(StatFs stat) {
long blockSize = stat.getBlockSize();
long totalBlocks = stat.getBlockCount();
return totalBlocks * blockSize;
}
private void addInformation(StringBuilder message) {
message.append("Locale: ").append(Locale.getDefault()).append('\n');
try {
PackageManager pm = context.getPackageManager();
PackageInfo pi;
pi = pm.getPackageInfo(context.getPackageName(), 0);
message.append("Version: ").append(pi.versionName).append('\n');
message.append("Package: ").append(pi.packageName).append('\n');
} catch (Exception e) {
Log.e("CustomExceptionHandler", "Error", e);
message.append("Could not get Version information for ").append(
context.getPackageName());
}
message.append("Phone Model: ").append(android.os.Build.MODEL).append(
'\n');
message.append("Android Version: ").append(
android.os.Build.VERSION.RELEASE).append('\n');
message.append("Board: ").append(android.os.Build.BOARD).append('\n');
message.append("Brand: ").append(android.os.Build.BRAND).append('\n');
message.append("Device: ").append(android.os.Build.DEVICE).append('\n');
message.append("Host: ").append(android.os.Build.HOST).append('\n');
message.append("ID: ").append(android.os.Build.ID).append('\n');
message.append("Model: ").append(android.os.Build.MODEL).append('\n');
message.append("Product: ").append(android.os.Build.PRODUCT).append(
'\n');
message.append("Type: ").append(android.os.Build.TYPE).append('\n');
StatFs stat = getStatFs();
message.append("Total Internal memory: ").append(
getTotalInternalMemorySize(stat)).append('\n');
message.append("Available Internal memory: ").append(
getAvailableInternalMemorySize(stat)).append('\n');
}
public void uncaughtException(Thread t, Throwable e) {
try {
StringBuilder report = new StringBuilder();
Date curDate = new Date();
report.append("Error Report collected on : ").append(curDate.toString()).append('\n').append('\n');
report.append("Informations :").append('\n');
addInformation(report);
report.append('\n').append('\n');
report.append("Stack:\n");
final Writer result = new StringWriter();
final PrintWriter printWriter = new PrintWriter(result);
e.printStackTrace(printWriter);
report.append(result.toString());
printWriter.close();
report.append('\n');
report.append("**** End of current Report ***");
Log.e(UnCaughtException.class.getName(),
"Error while sendErrorMail"+report);
sendErrorMail(report);
} catch (Throwable ignore) {
Log.e(UnCaughtException.class.getName(),
"Error while sending error e-mail", ignore);
}
// previousHandler.uncaughtException(t, e);
}
/**
* This method for call alert dialog when application crashed!
* #author vijayakumar
*/
public void sendErrorMail(final StringBuilder errorContent) {
final AlertDialog.Builder builder= new AlertDialog.Builder(context);
new Thread(){
#Override
public void run() {
Looper.prepare();
builder.setTitle("Sorry...!");
builder.create();
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
System.exit(0);
}
});
builder.setPositiveButton("Report", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Intent sendIntent = new Intent(Intent.ACTION_SEND);
String subject = "Your App crashed! Fix it!";
StringBuilder body = new StringBuilder("Yoddle");
body.append('\n').append('\n');
body.append(errorContent).append('\n').append('\n');
// sendIntent.setType("text/plain");
sendIntent.setType("message/rfc822");
sendIntent.putExtra(Intent.EXTRA_EMAIL, new String[] { RECIPIENT });
sendIntent.putExtra(Intent.EXTRA_TEXT, body.toString());
sendIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
sendIntent.setType("message/rfc822");
// context.startActivity(Intent.createChooser(sendIntent, "Error Report"));
context1.startActivity(sendIntent);
System.exit(0);
}
});
builder.setMessage("Unfortunately,This application has stopped");
builder.show();
Looper.loop();
}
}.start();
}
}
I'm making a Cloud Service that uses a standard HTTP get to get commands. I use a service (extending class IntentService as opposed to Service) to keep things in sync. I have the checking going on in a TimerTask firing off every 3 seconds. The problem is that when the user goes back to the activity to turn it off if they want, they press a toggle button. How do I tell the TimerTask (or the IntentService running a timer task) to stop and start it?
The service itself is getting destroyed after it handles the intent and creates the task, so would a Service be more appropriate for this than an IntentService? Even if thats the case, the question about stopping and starting the TimerTask remains.
Here's the code to the intentservice:
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import android.app.*;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Handler;
import android.widget.*;
public class syncservice extends IntentService {
/**
* A constructor is required, and must call the super IntentService(String)
* constructor with a name for the worker thread.
*/
public syncservice() {
super("syncservice");
}
public static final String PREFS_NAME = "prefcs";
/**
* The IntentService calls this method from the default worker thread with
* the intent that started the service. When this method returns, IntentService
* stops the service, as appropriate.
*/
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
final String uid = intent.getExtras().get("uid").toString();
final String dvname = intent.getExtras().get("dvname").toString();
final long period = intent.getExtras().getLong("period");
final Context ctx = getApplicationContext();
final Toast toast = Toast.makeText(ctx,"An error occured with the service. It will automatically turn off.", 0);
final Handler handler = new Handler();
TimerTask timertask = new TimerTask () {
#Override
public void run() {
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
if (settings.getBoolean("doservice", false)) {
String command = netread("url here");
//TODO Parse command from Pulling
if (command.contains("<")) {
//TODO what to do if an error occurred (exceptions already caught
Runnable showerrormessage = new Runnable() {
public void run() {
toast.makeText(ctx,"new text",0);
toast.show();
}
};
handler.post(showerrormessage);
}
}
}
};
Timer timer = new Timer();
timer.schedule(timertask,0,period);
return super.onStartCommand(intent,flags,startId);
}
public void onDestroy() {
Toast.makeText(getApplicationContext(), "The Service has died", Toast.LENGTH_SHORT).show();
return;
}
#Override
protected void onHandleIntent(Intent intent) {
Toast.makeText(getApplicationContext(), "Intent Handled", 0).show();
}
public final String netread(String url) {
try {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
ResponseHandler<String> resHandler = new BasicResponseHandler();
String page = httpClient.execute(httpGet, resHandler);
return page;
} catch (ClientProtocolException e) {
//Toast.makeText(getApplicationContext(),"Client Protocol Exception! Try again.",0).show();
return "<";
} catch (IOException e) {
//Toast.makeText(getApplicationContext(),"IO Exception! Make sure you are connected to the internet and try again.", 0).show();
return "<";
}
}
}
Thanks a bunch for helping me out!
For what you're trying to do, Handler may be more useful. That link BTW shows also how to stop it from the UI.