How to Customize “Force Close” Dialog in Android?

By | March 13, 2013

An interesting post..

Everytime you write an app, it may or may not crash and we often see the “Force Close” Dialog.
But what if we can customize the “Force Close” Dialog itself.

Force Close in Android

This is done using “UncaughtExceptionHandler” class.

This post explains this.
here I am knowingly crashing the application like this

int y = 5/0;

Now this is my MainActivity that is going to crash.

package com.coderzheaven.forceclosecustomize;

import android.app.Activity;
import android.os.Bundle;

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;
	}

}

And this is the Class that captures the Force Close Dialog and shows our CustomDialog.
UnCaughtException.java

package com.coderzheaven.forceclosecustomize;

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[] { "coderzheaven@gmail.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();
	}
}

6 thoughts on “How to Customize “Force Close” Dialog in Android?

  1. Francesco

    Sorry, it works pretty well… I just forgot the System.exit

    Reply
  2. Shashank

    Hi,Nice work…but I wan’t to ask whether we can replace email part with actual error reporting mechanism of google

    Reply
  3. Shrikant

    Hi, if not clicking cancel or Report and clicking back button .that time application not responsing please wait or close pop up got.

    Reply
  4. Pingback: Android: Catch Error “Unfortunately 'app' has stopped working” [closed] - Tutorial Guruji

  5. Pingback: Android: Catch Error "Unfortunately 'app' has stopped working"

Leave a Reply

Your email address will not be published. Required fields are marked *