View Javadoc

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  		// log the error
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  		// show notification
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 		// get the last item
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 }