さらに改善、したつもり
[ofnhwx.olib.git] / src / jp / gr / java_conf / ofnhwx / olib / ErrorReporter.java
blobe35e954350060a17e39eb36ed0321a4124896c1c
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 android.app.Activity;
14 import android.app.ActivityManager;
15 import android.app.ActivityManager.MemoryInfo;
16 import android.app.AlertDialog;
17 import android.content.ActivityNotFoundException;
18 import android.content.Context;
19 import android.content.DialogInterface;
20 import android.content.DialogInterface.OnCancelListener;
21 import android.content.DialogInterface.OnClickListener;
22 import android.content.Intent;
23 import android.content.pm.PackageInfo;
24 import android.content.pm.PackageManager;
25 import android.content.pm.PackageManager.NameNotFoundException;
26 import android.graphics.Bitmap;
27 import android.graphics.drawable.BitmapDrawable;
28 import android.net.Uri;
29 import android.os.Build;
30 import android.util.Log;
31 import android.widget.Toast;
33 /**
34 * バグ報告用のクラス(頂いてきた).
35 * @author yuta
37 public final class ErrorReporter implements UncaughtExceptionHandler {
39 private static final String TAG = ErrorReporter.class.getSimpleName();
41 private static final UncaughtExceptionHandler DEFAULT_HANDLER = Thread.getDefaultUncaughtExceptionHandler();
42 private static final String ERROR_FILE = "BUG";
43 private static final String REPORT_FILE = "REPORT";
44 private static Context sContext = null;
45 private static PackageInfo sPackageInfo = null;
47 /**
48 * バグ報告の準備、各Activityのなるべく早い段階で呼び出すこと.
49 * @param context 基本的には{@code this}を指定
51 public static void initialize(Context context) {
53 // 2回目以降は何もしない
54 if (sContext != null) {
55 return;
58 // 標準の例外処理をすり替える
59 sContext = context.getApplicationContext();
60 try {
61 PackageManager pm = sContext.getPackageManager();
62 sPackageInfo = pm.getPackageInfo(sContext.getPackageName(), 0);
63 } catch (NameNotFoundException e) {
64 e.printStackTrace();
66 Thread.setDefaultUncaughtExceptionHandler(new ErrorReporter());
70 /**
71 * エラー報告の確認を行うダイアログを表示する.
72 * @param activity ダイアログを表示するアクティビティ
73 * @param dialogId 表示するダイアログの{@code id}
75 public static final void show(Activity activity, int dialogId) {
76 File file = activity.getFileStreamPath(ERROR_FILE);
77 if (!file.exists()) {
78 return;
80 activity.showDialog(dialogId);
83 /**
84 * エラー報告の確認を行うダイアログを取得する.
85 * @param activity
86 * @param icon
87 * @return
89 public static final AlertDialog getDialog(final Activity activity, int icon) {
91 // エラーファイル
92 final File file = activity.getFileStreamPath(ERROR_FILE);
94 // 表示するアイコン
95 float density = activity.getResources().getDisplayMetrics().density;
96 Bitmap bitmap = OBitmap.decodeResource(activity, icon, (int)(32 * density));
98 // ダイアログの初期設定
99 AlertDialog.Builder dialog = new AlertDialog.Builder(activity);
100 dialog.setIcon(new BitmapDrawable(bitmap));
101 dialog.setTitle(R.string.bug_report_title);
102 dialog.setMessage(R.string.bug_report_message);
104 // エラー内容を送信する
105 dialog.setPositiveButton(R.string.bug_report_positive, new OnClickListener() {
106 public void onClick(DialogInterface dialog, int which) {
107 sendBugreport(activity, file);
111 // エラー内容を送信しない
112 dialog.setNegativeButton(R.string.bug_report_negative, new OnClickListener() {
113 public void onClick(DialogInterface dialog, int which) {
114 if (!file.delete()) {
115 Log.e(TAG, "Couldn't delete error file.");
120 // キャンセル
121 dialog.setOnCancelListener(new OnCancelListener() {
122 public void onCancel(DialogInterface dialog) {
123 if (!file.delete()) {
124 Log.e(TAG, "Couldn't delete error file.");
129 // ダイアログを返す
130 return dialog.create();
135 * エラー報告の送信.
136 * @param activity
137 * @param errorFile
138 * @throws IOException
140 private static final void sendBugreport(Context context, File errorFile) {
142 // バグ報告ファイルをリネーム
143 File file = context.getFileStreamPath(REPORT_FILE);
144 if (!errorFile.exists() || !errorFile.renameTo(file)) {
145 return;
149 BufferedReader reader;
150 try {
151 reader = new BufferedReader(new FileReader(file));
152 } catch (FileNotFoundException e) {
153 // 何もしない
154 return;
158 String subject;
159 StringBuilder text = new StringBuilder();
160 try {
161 subject = reader.readLine();
162 text.append(subject).append("\n");
163 String line;
164 while ((line = reader.readLine()) != null) {
165 text.append(line).append("\n");
167 } catch (IOException e) {
168 return;
169 } finally {
170 try { reader.close(); } catch (Exception e) {}
171 if (!file.delete()) {
172 Log.e(TAG, "Can't delete report file.");
176 // メールの送信
177 String[] mail = new String[] { context.getString(R.string.mail) };
178 Intent intent = new Intent();
179 intent.setAction(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 context.startActivity(intent);
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 context.startActivity(intent);
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);