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.getLocalizedMessage());
92 }
93 final String errorText = text.toString();
94 errors.add(new ErrorInfo(error, errorText, cause));
95 AmbientApplication.getHandler().post(new Runnable() {
96 public void run() {
97 final Toast toast = Toast.makeText(app, errorText,
98 Toast.LENGTH_LONG);
99 toast.show();
100 updateNotification();
101 }
102 });
103 }
104
105 /***
106 * Contains information about an error.
107 *
108 * @author Martin Vysny
109 */
110 public static class ErrorInfo {
111 /***
112 * The time the error occurred.
113 */
114 public final long timestamp;
115 /***
116 * <code>true</code> on error, <code>false</code> on warning.
117 */
118 public final boolean error;
119 /***
120 * The message.
121 */
122 public final String message;
123 /***
124 * The stack trace.
125 */
126 public final String stacktrace;
127
128 /***
129 * Creates new error information object.
130 *
131 * @param error
132 * <code>true</code> on error, <code>false</code> on warning.
133 * @param message
134 * The message.
135 * @param t
136 * the cause.
137 */
138 public ErrorInfo(final boolean error, final String message,
139 final Throwable t) {
140 super();
141 timestamp = System.currentTimeMillis();
142 this.error = error;
143 this.message = message;
144 this.stacktrace = t == null ? null : MiscUtils.getStackTrace(t);
145 }
146 }
147
148 private final Queue<ErrorInfo> errors = new ConcurrentLinkedQueue<ErrorInfo>();
149
150 /***
151 * Returns a new copy of the recorded error list.
152 *
153 * @return non-<code>null</code> list of errors.
154 */
155 public List<ErrorInfo> getErrors() {
156 return new ArrayList<ErrorInfo>(errors);
157 }
158
159 /***
160 * Clears all recorded error messages. Must be invoked from the
161 * {@link Handler} thread.
162 */
163 public void clear() {
164 errors.clear();
165 updateNotification();
166 }
167
168 private void updateNotification() {
169
170 ErrorInfo last = null;
171 int size = 0;
172 for (final ErrorInfo ei : errors) {
173 last = ei;
174 size++;
175 }
176 app.getNotificator().updateErrorNotification(size, last);
177 }
178 }