1 /***
2 * Ambient - A music player for the Android platform
3 Copyright (C) 2007 Martin Vysny
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 package sk.baka.ambient;
20
21 import java.util.ArrayList;
22 import java.util.List;
23 import java.util.Queue;
24 import java.util.concurrent.ConcurrentLinkedQueue;
25
26 import sk.baka.ambient.commons.MiscUtils;
27 import android.os.Handler;
28 import android.util.Log;
29 import android.widget.Toast;
30
31 /***
32 * Handles errors that occurs in the application. Thread-safe.
33 *
34 * @author Martin Vysny
35 *
36 */
37 public final class ErrorHandler {
38
39 private final AmbientApplication app;
40
41 /***
42 * Creates new handler instance.
43 *
44 * @param app
45 * owner application.
46 */
47 ErrorHandler(final AmbientApplication app) {
48 this.app = app;
49 }
50
51 /***
52 * An error occurred. A notification will be shown to the user.
53 *
54 * @param sender
55 * the sender.
56 * @param error
57 * error if <code>true</code>, warning if <code>false</code>.
58 * @param message
59 * the message to show. The message will be followed by a new
60 * line, the <code>Cause: </code> string and the
61 * {@link Throwable#getMessage()} if the cause is not
62 * <code>null</code>.
63 * @param cause
64 * optional cause.
65 */
66 public void error(final Class<?> sender, boolean error, String message,
67 Throwable cause) {
68
69 if (error) {
70 if (cause != null) {
71 Log.e(sender.getSimpleName(), message, cause);
72 } else {
73 Log.e(sender.getSimpleName(), message);
74 }
75 } else {
76 if (cause != null) {
77 Log.w(sender.getSimpleName(), message, cause);
78 } else {
79 Log.w(sender.getSimpleName(), message);
80 }
81 }
82
83 final StringBuilder text = new StringBuilder();
84 text.append(app.getString(error ? R.string.error : R.string.warning));
85 text.append(": ");
86 text.append(message);
87 if (cause != null) {
88 text.append('\n');
89 text.append(app.getString(R.string.cause));
90 text.append(": ");
91 text.append(cause.getClass().getSimpleName());
92 text.append(": ");
93 text.append(cause.getLocalizedMessage());
94 }
95 final String errorText = text.toString();
96 errors.add(new ErrorInfo(error, errorText, cause));
97 AmbientApplication.getHandler().post(new Runnable() {
98 public void run() {
99 final Toast toast = Toast.makeText(app, errorText,
100 Toast.LENGTH_LONG);
101 toast.show();
102 updateNotification();
103 }
104 });
105 }
106
107 /***
108 * Contains information about an error.
109 *
110 * @author Martin Vysny
111 */
112 public static class ErrorInfo {
113 /***
114 * The time the error occurred.
115 */
116 public final long timestamp;
117 /***
118 * <code>true</code> on error, <code>false</code> on warning.
119 */
120 public final boolean error;
121 /***
122 * The message.
123 */
124 public final String message;
125 /***
126 * The stack trace.
127 */
128 public final String stacktrace;
129
130 /***
131 * Creates new error information object.
132 *
133 * @param error
134 * <code>true</code> on error, <code>false</code> on warning.
135 * @param message
136 * The message.
137 * @param t
138 * the cause.
139 */
140 public ErrorInfo(final boolean error, final String message,
141 final Throwable t) {
142 super();
143 timestamp = System.currentTimeMillis();
144 this.error = error;
145 this.message = message;
146 this.stacktrace = t == null ? null : MiscUtils.getStackTrace(t);
147 }
148 }
149
150 private final Queue<ErrorInfo> errors = new ConcurrentLinkedQueue<ErrorInfo>();
151
152 /***
153 * Returns a new copy of the recorded error list.
154 *
155 * @return non-<code>null</code> list of errors.
156 */
157 public List<ErrorInfo> getErrors() {
158 return new ArrayList<ErrorInfo>(errors);
159 }
160
161 /***
162 * Clears all recorded error messages. Must be invoked from the
163 * {@link Handler} thread.
164 */
165 public void clear() {
166 errors.clear();
167 updateNotification();
168 }
169
170 private void updateNotification() {
171
172 ErrorInfo last = null;
173 int size = 0;
174 for (final ErrorInfo ei : errors) {
175 last = ei;
176 size++;
177 }
178 app.getNotificator().updateErrorNotification(size, last);
179 }
180 }