recycleしすぎてた?
[ofnhwx.olib.git] / src / jp / gr / java_conf / ofnhwx / olib / ErrorReporter.java
blob02233f6fd8167a65b40623eb14c527289529e9e4
1 package jp.gr.java_conf.ofnhwx.olib;
3 import java.io.BufferedReader;
4 import java.io.File;
5 import java.io.FileNotFoundException;
6 import java.io.FileOutputStream;
7 import java.io.FileReader;
8 import java.io.IOException;
9 import java.io.PrintWriter;
10 import java.lang.Thread.UncaughtExceptionHandler;
12 import jp.gr.java_conf.ofnhwx.olib.utils.OBitmap;
13 import jp.gr.java_conf.ofnhwx.olib.utils.OUtil;
14 import android.app.Activity;
15 import android.app.ActivityManager;
16 import android.app.ActivityManager.MemoryInfo;
17 import android.app.AlertDialog;
18 import android.content.ActivityNotFoundException;
19 import android.content.Context;
20 import android.content.DialogInterface;
21 import android.content.DialogInterface.OnCancelListener;
22 import android.content.DialogInterface.OnClickListener;
23 import android.content.Intent;
24 import android.content.pm.PackageInfo;
25 import android.content.pm.PackageManager;
26 import android.content.pm.PackageManager.NameNotFoundException;
27 import android.graphics.Bitmap;
28 import android.graphics.drawable.BitmapDrawable;
29 import android.net.Uri;
30 import android.os.Build;
31 import android.util.Log;
32 import android.widget.Toast;
34 /**
35 * バグ報告用のクラス(頂いてきた).
36 * @author yuta
38 public final class ErrorReporter implements UncaughtExceptionHandler {
40 private static final String TAG = ErrorReporter.class.getSimpleName();
42 private static final UncaughtExceptionHandler DEFAULT_HANDLER = Thread.getDefaultUncaughtExceptionHandler();
43 private static final String ERROR_FILE = "BUG";
44 private static final String REPORT_FILE = "REPORT";
45 private static Context sContext = null;
46 private static PackageInfo sPackageInfo = null;
48 /**
49 * バグ報告の準備、各Activityのなるべく早い段階で呼び出すこと.
50 * @param context 基本的には{@code this}を指定
52 public static void initialize(Context context) {
54 // 2回目以降は何もしない
55 if (sContext != null) {
56 return;
59 // 標準の例外処理をすり替える
60 sContext = context.getApplicationContext();
61 try {
62 PackageManager pm = sContext.getPackageManager();
63 sPackageInfo = pm.getPackageInfo(sContext.getPackageName(), 0);
64 } catch (NameNotFoundException e) {
65 e.printStackTrace();
67 Thread.setDefaultUncaughtExceptionHandler(new ErrorReporter());
71 /**
72 * エラー報告の確認を行うダイアログを表示する.
73 * @param activity ダイアログを表示するアクティビティ
74 * @param dialogId 表示するダイアログの{@code id}
76 public static final void show(Activity activity, int dialogId) {
77 File file = activity.getFileStreamPath(ERROR_FILE);
78 if (!file.exists()) {
79 return;
81 activity.showDialog(dialogId);
84 /**
85 * エラー報告の確認を行うダイアログを取得する.
86 * @param activity
87 * @param icon
88 * @return
90 public static final AlertDialog getDialog(final Activity activity, int icon) {
92 // エラーファイル
93 final File file = activity.getFileStreamPath(ERROR_FILE);
95 // 表示するアイコン
96 float density = activity.getResources().getDisplayMetrics().density;
97 Bitmap bitmap = OBitmap.decodeResource(activity, icon, (int)(32 * density));
99 // ダイアログの初期設定
100 AlertDialog.Builder dialog = new AlertDialog.Builder(activity);
101 dialog.setIcon(new BitmapDrawable(bitmap));
102 dialog.setTitle(R.string.bug_report_title);
103 dialog.setMessage(R.string.bug_report_message);
105 // エラー内容を送信する
106 dialog.setPositiveButton(R.string.bug_report_positive, new OnClickListener() {
107 public void onClick(DialogInterface dialog, int which) {
108 sendBugreport(activity, file);
112 // エラー内容を送信しない
113 dialog.setNegativeButton(R.string.bug_report_negative, new OnClickListener() {
114 public void onClick(DialogInterface dialog, int which) {
115 if (!file.delete()) {
116 Log.e(TAG, "Couldn't delete error file.");
121 // キャンセル
122 dialog.setOnCancelListener(new OnCancelListener() {
123 public void onCancel(DialogInterface dialog) {
124 if (!file.delete()) {
125 Log.e(TAG, "Couldn't delete error file.");
130 // ダイアログを返す
131 return dialog.create();
136 * エラー報告の送信.
137 * @param activity
138 * @param errorFile
139 * @throws IOException
141 private static final void sendBugreport(Context context, File errorFile) {
143 // バグ報告ファイルをリネーム
144 File file = context.getFileStreamPath(REPORT_FILE);
145 if (!errorFile.exists() || !errorFile.renameTo(file)) {
146 return;
150 BufferedReader reader;
151 try {
152 reader = new BufferedReader(new FileReader(file));
153 } catch (FileNotFoundException e) {
154 // 何もしない
155 return;
159 String subject;
160 StringBuilder text = new StringBuilder();
161 try {
162 subject = reader.readLine();
163 text.append(subject).append("\n");
164 String line;
165 while ((line = reader.readLine()) != null) {
166 text.append(line).append("\n");
168 } catch (IOException e) {
169 return;
170 } finally {
171 try { reader.close(); } catch (Exception e) {}
172 if (!file.delete()) {
173 Log.e(TAG, "Can't delete report file.");
177 // メールの送信
178 String[] mail = new String[] { context.getString(R.string.mail) };
179 Intent intent = new Intent(Intent.ACTION_SEND);
180 intent.setType("message/rfc822");
181 intent.putExtra(Intent.EXTRA_EMAIL, mail);
182 intent.putExtra(Intent.EXTRA_SUBJECT, subject);
183 intent.putExtra(Intent.EXTRA_TEXT, text.toString());
184 try {
185 OUtil.sendChoiceIntent(context, intent, R.string.choose_mailer);
186 } catch (ActivityNotFoundException e) {
187 String mailTo = context.getString(R.string.mail_to);
188 intent = new Intent(Intent.ACTION_SENDTO, Uri.parse(mailTo));
189 intent.putExtra(Intent.EXTRA_SUBJECT, subject);
190 intent.putExtra(Intent.EXTRA_TEXT, text.toString());
191 try {
192 OUtil.sendChoiceIntent(context, intent, R.string.choose_mailer);
193 } catch (ActivityNotFoundException e2) {
194 Toast.makeText(context, "Activity not found.", Toast.LENGTH_SHORT).show();
201 * {@inheritDoc}
203 public void uncaughtException(Thread thread, Throwable error) {
205 // スタックトレースの出力
206 error.printStackTrace();
208 // ファイルの準備
209 PrintWriter writer;
210 try {
211 FileOutputStream fos = sContext.openFileOutput(ERROR_FILE, Context.MODE_WORLD_READABLE);
212 writer = new PrintWriter(fos);
213 } catch (FileNotFoundException e) {
214 // ここには到達しない、しても何もしない
215 return;
218 // パッケージ情報の記録
219 if (sPackageInfo != null) {
220 writer.printf("[BUG][%s] versionName:%s, versionCode:%d\n",
221 sPackageInfo.packageName,
222 sPackageInfo.versionName,
223 sPackageInfo.versionCode);
224 } else {
225 writer.printf("[BUG][Unkown Package]\n");
228 // メモリ情報の記録(Total, Free, Used)
229 long total = Runtime.getRuntime().totalMemory() / 1024;
230 long free = Runtime.getRuntime().freeMemory() / 1024;
231 writer.printf("Runtime Memory: total: %dKB, free: %dKB, used: %dKB\n",
232 total, free, total - free);
234 // メモリ情報の記録(Avail, LowMemory)
235 ActivityManager am = (ActivityManager)sContext.getSystemService(Context.ACTIVITY_SERVICE);
236 MemoryInfo info = new MemoryInfo();
237 am.getMemoryInfo(info);
238 writer.printf("availMem: %dKB, lowMemory: %b\n",
239 info.availMem / 1024, info.lowMemory);
241 // デバイス情報の記録
242 writer.printf("DEVICE: %s\n", Build.DEVICE);
243 writer.printf("MODEL : %s\n", Build.MODEL);
244 writer.printf("VERSION.SDK: %s\n", Build.VERSION.SDK);
245 writer.printf("\n");
247 // スタックトレースを記録
248 error.printStackTrace(writer);
250 // ファイルを保存して閉じる
251 writer.close();
253 // ここで終了
254 DEFAULT_HANDLER.uncaughtException(thread, error);