Android Open Source - My-Wallet-Android Error Reporter






From Project

Back to project page My-Wallet-Android.

License

The source code is released under:

GNU General Public License

If you think the Android project My-Wallet-Android listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright 2011-2012 the original author or authors.
 *// w w w . ja v a2  s. c o m
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package piuk.blockchain.android.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Date;
import java.util.Formatter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import piuk.blockchain.android.Constants;


import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Environment;
import android.os.StatFs;

/**
 * @author Andreas Schildbach
 */
public class ErrorReporter implements Thread.UncaughtExceptionHandler
{
  private static final String STACKTRACE_FILENAME = ".stacktrace";
  private static final String REPORT_SUBJECT = "Blockchain Crash Report";
  private static final String REPORT_EMAIL = "wallet@schildbach.de";
  private static final String DIALOG_TITLE = "Previous crash detected";
  private static final String DIALOG_MESSAGE = "Would you like to send a crash report, helping to fix this issue in the future?";

  private Thread.UncaughtExceptionHandler previousHandler;
  private File stackTraceFile;
  private final StringBuilder report = new StringBuilder();
  private File filesDir, cacheDir;

  private static ErrorReporter instance;

  public static ErrorReporter getInstance()
  {
    if (instance == null)
      instance = new ErrorReporter();
    return instance;
  }

  public synchronized void init(final Context context)
  {
    previousHandler = Thread.getDefaultUncaughtExceptionHandler();
    Thread.setDefaultUncaughtExceptionHandler(this);

    filesDir = context.getFilesDir();
    cacheDir = context.getCacheDir();

    stackTraceFile = new File(cacheDir, STACKTRACE_FILENAME);

    report.append("=== collected at launch time ===\n\n");
    report.append("Test: " + Constants.TEST + "\n\n");
    appendReport(report, context);
  }

  private static void appendReport(final StringBuilder report, final Context context)
  {
    try
    {
      final PackageManager pm = context.getPackageManager();
      final PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
      final Resources res = context.getResources();
      final Configuration config = res.getConfiguration();

      report.append("Date: " + new Date() + "\n");
      report.append("Version: " + pi.versionName + " (" + pi.versionCode + ")\n");
      report.append("Package: " + pi.packageName + "\n");
      report.append("Phone Model: " + android.os.Build.MODEL + "\n");
      report.append("Android Version: " + android.os.Build.VERSION.RELEASE + "\n");
      report.append("Board: " + android.os.Build.BOARD + "\n");
      report.append("Brand: " + android.os.Build.BRAND + "\n");
      report.append("Device: " + android.os.Build.DEVICE + "\n");
      report.append("Display: " + android.os.Build.DISPLAY + "\n");
      report.append("Finger Print: " + android.os.Build.FINGERPRINT + "\n");
      report.append("Host: " + android.os.Build.HOST + "\n");
      report.append("ID: " + android.os.Build.ID + "\n");
      // report.append("Manufacturer: " + manufacturer + "\n");
      report.append("Model: " + android.os.Build.MODEL + "\n");
      report.append("Product: " + android.os.Build.PRODUCT + "\n");
      report.append("Tags: " + android.os.Build.TAGS + "\n");
      report.append("Time: " + android.os.Build.TIME + "\n");
      report.append("Type: " + android.os.Build.TYPE + "\n");
      report.append("User: " + android.os.Build.USER + "\n");
      report.append("Configuration: " + config + "\n");
      report.append("ScreenLayout: size " + (config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) + " long "
          + (config.screenLayout & Configuration.SCREENLAYOUT_LONG_MASK) + "\n");
      report.append("DisplayMetrics: " + res.getDisplayMetrics() + "\n");
      report.append("Databases:");
      for (final String db : context.databaseList())
        report.append(" " + db);
      report.append("\n\n\n");
    }
    catch (NameNotFoundException e)
    {
      e.printStackTrace();
    }
  }

  private long getAvailableInternalMemorySize()
  {
    final File path = Environment.getDataDirectory();
    final StatFs stat = new StatFs(path.getPath());
    final long blockSize = stat.getBlockSize();
    final long availableBlocks = stat.getAvailableBlocks();
    return availableBlocks * blockSize;
  }

  private long getTotalInternalMemorySize()
  {
    final File path = Environment.getDataDirectory();
    final StatFs stat = new StatFs(path.getPath());
    final long blockSize = stat.getBlockSize();
    final long totalBlocks = stat.getBlockCount();
    return totalBlocks * blockSize;
  }

  public synchronized void uncaughtException(final Thread t, final Throwable e)
  {
    report.append("=== collected at exception time ===\n\n");

    report.append("Total Internal memory: " + getTotalInternalMemorySize() + "\n");
    report.append("Available Internal memory: " + getAvailableInternalMemorySize() + "\n");
    report.append("\n");

    final Writer result = new StringWriter();
    final PrintWriter printWriter = new PrintWriter(result);
    e.printStackTrace(printWriter);
    final String stacktrace = result.toString();
    report.append(stacktrace + "\n");

    // If the exception was thrown in a background thread inside
    // AsyncTask, then the actual exception can be found with getCause
    Throwable cause = e.getCause();
    while (cause != null)
    {
      cause.printStackTrace(printWriter);
      report.append("Cause:\n");
      report.append(result.toString() + "\n");
      cause = cause.getCause();
    }
    printWriter.close();

    // append contents of directories
    report.append("\nContents of FilesDir " + filesDir + ":\n");
    appendReport(report, filesDir, 0);
    report.append("\nContents of CacheDir " + cacheDir + ":\n");
    appendReport(report, cacheDir, 0);

    saveAsFile(report.toString());

    previousHandler.uncaughtException(t, e);
  }

  private static void sendErrorMail(final Context context, final String errorContent)
  {
    final Intent sendIntent = new Intent(Intent.ACTION_SEND);
    final Matcher m = Pattern.compile("Version: (.+?) ").matcher(errorContent);
    final String versionName = m.find() ? m.group(1) : "";
    final String subject = REPORT_SUBJECT + " " + versionName;
    sendIntent.putExtra(Intent.EXTRA_EMAIL, new String[] { REPORT_EMAIL });
    sendIntent.putExtra(Intent.EXTRA_TEXT, errorContent);
    sendIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
    sendIntent.setType("message/rfc822");
    context.startActivity(Intent.createChooser(sendIntent, "Send Crash Report using..."));
  }

  public static void sendBugMail(final Context context)
  {
    final StringBuilder report = new StringBuilder();
    report.append("   Welchen Programmteil betrifft Dein Problem? (siehe erste Zeile des Fenstertitels)\n");
    report.append("   Which application component does your issue apply to? (first line of window title)\n");
    report.append("\n\n");
    report.append("   Welches Verkehrsnetz hast Du eingestellt? (siehe zweite Zeile des Fenstertitels)\n");
    report.append("   Which transport network have you got selected? (second line of window title)\n");
    report.append("\n\n");
    report.append("   Hast Du schon auf aktuellere ffi-Versionen geprft?\n");
    report.append("   Did you already check for new versions of ffi?\n");
    report.append("\n\n");
    report.append("\n=== collected at reporting time ===\n\n");
    appendReport(report, context);

    // append contents of directories
    report.append("\nContents of FilesDir " + context.getFilesDir() + ":\n");
    appendReport(report, context.getFilesDir(), 0);
    report.append("\nContents of CacheDir " + context.getCacheDir() + ":\n");
    appendReport(report, context.getCacheDir(), 0);

    final Intent sendIntent = new Intent(Intent.ACTION_SEND);
    sendIntent.putExtra(Intent.EXTRA_EMAIL, new String[] { REPORT_EMAIL });
    sendIntent.putExtra(Intent.EXTRA_TEXT, report.toString());
    sendIntent.putExtra(Intent.EXTRA_SUBJECT, REPORT_SUBJECT);
    sendIntent.setType("message/rfc822");
    context.startActivity(Intent.createChooser(sendIntent, "Send Bug Report using..."));
  }

  private void saveAsFile(final String errorContent)
  {
    try
    {
      final FileOutputStream trace = new FileOutputStream(stackTraceFile);
      trace.write(errorContent.getBytes());
      trace.close();
    }
    catch (final IOException x)
    {
      // swallow
    }
  }

  private void sendError(final Context context)
  {
    try
    {
      final StringBuilder errorText = new StringBuilder();

      final BufferedReader input = new BufferedReader(new FileReader(stackTraceFile));
      String line;
      while ((line = input.readLine()) != null)
        errorText.append(line + "\n");
      input.close();

      sendErrorMail(context, errorText.toString());
    }
    catch (Exception x)
    {
      x.printStackTrace();
    }
  }

  private static void appendReport(final StringBuilder report, final File file, final int indent)
  {
    final Formatter formatter = new Formatter(report);

    for (int i = 0; i < indent; i++)
      report.append("  - ");
    formatter.format("%tF %tT  %s  [%d]\n", file.lastModified(), file.lastModified(), file.getName(), file.length());

    if (file.isDirectory())
      for (final File f : file.listFiles())
        appendReport(report, f, indent + 1);
  }

  public synchronized void check(final Context context)
  {
    if (!stackTraceFile.exists())
      return;

    final Builder builder = new AlertDialog.Builder(context).setIcon(android.R.drawable.ic_dialog_alert).setTitle(DIALOG_TITLE)
        .setMessage(DIALOG_MESSAGE);
    builder.setPositiveButton("Report", new OnClickListener()
    {
      public void onClick(final DialogInterface dialog, final int which)
      {
        sendError(context);
        stackTraceFile.delete();
      }
    });
    builder.setNegativeButton("Dismiss", new OnClickListener()
    {
      public void onClick(final DialogInterface dialog, final int which)
      {
        stackTraceFile.delete();
        dialog.dismiss();
      }
    });

    try
    {
      builder.show();
    }
    catch (final Exception x)
    {
      // swallow
    }
  }
}




Java Source Code List

piuk.BitcoinAddress.java
piuk.BitcoinScript.java
piuk.Hash.java
piuk.MyBlockChain.java
piuk.MyRemoteWallet.java
piuk.MyTransactionConfidence.java
piuk.MyTransactionInput.java
piuk.MyTransactionOutPoint.java
piuk.MyTransactionOutput.java
piuk.MyTransaction.java
piuk.MyWallet.java
piuk.blockchain.android.AddressBookProvider.java
piuk.blockchain.android.BlockchainService.java
piuk.blockchain.android.Constants.java
piuk.blockchain.android.DetermineFirstSeenThread.java
piuk.blockchain.android.ExchangeRatesProvider.java
piuk.blockchain.android.WalletApplication.java
piuk.blockchain.android.WalletBalanceWidgetProvider.java
piuk.blockchain.android.ui.AbstractWalletActivity.java
piuk.blockchain.android.ui.AmountCalculatorFragment.java
piuk.blockchain.android.ui.CurrencyAmountView.java
piuk.blockchain.android.ui.CurrencyCodeDrawable.java
piuk.blockchain.android.ui.EditAddressBookEntryFragment.java
piuk.blockchain.android.ui.ExchangeRatesFragment.java
piuk.blockchain.android.ui.NewAccountFragment.java
piuk.blockchain.android.ui.PairWalletActivity.java
piuk.blockchain.android.ui.PreferencesActivity.java
piuk.blockchain.android.ui.RequestCoinsActivity.java
piuk.blockchain.android.ui.RequestCoinsFragment.java
piuk.blockchain.android.ui.SecondPasswordFragment.java
piuk.blockchain.android.ui.SendCoinsActivity.java
piuk.blockchain.android.ui.SendCoinsFragment.java
piuk.blockchain.android.ui.SendingAddressesFragment.java
piuk.blockchain.android.ui.TransactionActivity.java
piuk.blockchain.android.ui.TransactionFragment.java
piuk.blockchain.android.ui.WalletActivity.java
piuk.blockchain.android.ui.WalletAddressesFragment.java
piuk.blockchain.android.ui.WalletBalanceFragment.java
piuk.blockchain.android.ui.WalletTransactionsFragment.java
piuk.blockchain.android.ui.WelcomeFragment.java
piuk.blockchain.android.util.ActionBarFragment.java
piuk.blockchain.android.util.Base43.java
piuk.blockchain.android.util.CircularProgressView.java
piuk.blockchain.android.util.ErrorReporter.java
piuk.blockchain.android.util.IOUtils.java
piuk.blockchain.android.util.Iso8601Format.java
piuk.blockchain.android.util.NfcTools.java
piuk.blockchain.android.util.QrDialog.java
piuk.blockchain.android.util.ViewPagerTabs.java
piuk.blockchain.android.util.WalletUtils.java