1   /**
2    * MicroEmulator 
3    * Copyright (C) 2007 Rushabh Doshi <radoshi@cs.stanford.edu> Pelago, Inc
4    * 
5    * This library is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as published by the
7    * Free Software Foundation; either version 2.1 of the License, or (at your
8    * option) any later version.
9    * 
10   * This library is distributed in the hope that it will be useful, but WITHOUT
11   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12   * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
13   * for more details.
14   * 
15   * You should have received a copy of the GNU Lesser General Public License
16   * along with this library; if not, write to the Free Software Foundation,
17   * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18   * 
19   * Contributor(s): 
20   *   3GLab
21   *   Andres Navarro
22   *   
23   *  @version $Id: DisplayTest.java 1579 2008-02-11 14:50:58Z barteo $
24   */
25  package javax.microedition.lcdui;
26  
27  import java.io.IOException;
28  import java.io.InputStream;
29  import java.util.Map;
30  import java.util.Vector;
31  
32  import junit.framework.TestCase;
33  
34  import org.microemu.device.Device;
35  import org.microemu.device.DeviceDisplay;
36  import org.microemu.device.DeviceFactory;
37  import org.microemu.device.FontManager;
38  import org.microemu.device.InputMethod;
39  import org.microemu.device.MutableImage;
40  import org.microemu.device.ui.UIFactory;
41  
42  /**
43   * @author radoshi
44   * 
45   */
46  public class DisplayTest extends TestCase {
47  
48  	private final static class MockDisplayable extends Displayable {
49  
50  		volatile int prePaintCount = 0, postPaintCount = 0;
51  
52  		/**
53  		 * 
54  		 */
55  		public MockDisplayable() {
56  
57  			super("Mock");
58  		}
59  
60  		final void paint(Graphics g) {
61  
62  			prePaintCount++;
63  
64  			synchronized (this) {
65  
66  				try {
67  					this.wait();
68  				} catch (InterruptedException exception) {
69  					exception.printStackTrace();
70  				}
71  			}
72  
73  			postPaintCount++;
74  		}
75  
76  		final void reset() {
77  
78  			this.prePaintCount = 0;
79  			this.postPaintCount = 0;
80  		}
81  	}
82  
83  	private final static class MockRunner implements Runnable {
84  
85  		volatile boolean hasRun = false;
86  
87  		public final void run() {
88  
89  			hasRun = true;
90  		}
91  
92  		final void reset() {
93  
94  			hasRun = false;
95  		}
96  
97  	}
98  
99  	private static final class MockDeviceDisplay implements DeviceDisplay {
100 
101 		private int width = 100, height = 100;
102 
103 		private Display display;
104 
105 		/**
106 		 * @param display
107 		 */
108 		public MockDeviceDisplay(Display display) {
109 
110 			assertNotNull(display);
111 			this.display = display;
112 		}
113 
114 		public Image createImage(int width, int height) {
115 
116 			return null;
117 		}
118 
119 		public Image createImage(String name) throws IOException {
120 
121 			return null;
122 		}
123 
124 		public Image createImage(Image source) {
125 
126 			return null;
127 		}
128 
129 		public Image createImage(	byte[] imageData,
130 									int imageOffset,
131 									int imageLength) {
132 
133 			return null;
134 		}
135 
136 		public Image createImage(InputStream is) throws IOException {
137 
138 			return null;
139 		}
140 
141 		public Image createImage(	Image image,
142 									int x,
143 									int y,
144 									int width,
145 									int height,
146 									int transform) {
147 
148 			return null;
149 		}
150 
151 		public Image createRGBImage(int[] rgb,
152 									int width,
153 									int height,
154 									boolean processAlpha) {
155 
156 			return null;
157 		}
158 
159 		public MutableImage getDisplayImage() {
160 
161 			return null;
162 		}
163 
164 		public int getFullHeight() {
165 
166 			return this.height;
167 		}
168 
169 		public int getFullWidth() {
170 
171 			return this.width;
172 		}
173 
174 		public int getHeight() {
175 
176 			return this.height;
177 		}
178 
179 		public int getWidth() {
180 
181 			return this.width;
182 		}
183 
184 		public boolean isColor() {
185 
186 			return false;
187 		}
188 
189 		public boolean isFullScreenMode() {
190 
191 			return false;
192 		}
193 
194 		public int numAlphaLevels() {
195 
196 			return 0;
197 		}
198 
199 		public int numColors() {
200 
201 			return 0;
202 		}
203 
204 		public void repaint(int x, int y, int width, int height) {
205 
206 			display.getCurrent().paint(null);
207 		}
208 
209 		public void setScrollDown(boolean state) {
210 
211 		}
212 
213 		public void setScrollUp(boolean state) {
214 
215 		}
216 
217 	}
218 
219 	private static final class MockFontManager implements FontManager {
220 
221 		public int charWidth(Font f, char ch) {
222 
223 			return 0;
224 		}
225 
226 		public int charsWidth(Font f, char[] ch, int offset, int length) {
227 
228 			return 0;
229 		}
230 
231 		public int getBaselinePosition(Font f) {
232 
233 			return 0;
234 		}
235 
236 		public int getHeight(Font f) {
237 
238 			return 0;
239 		}
240 
241 		public void init() {
242 
243 		}
244 
245 		public int stringWidth(Font f, String str) {
246 
247 			return 0;
248 		}
249 
250 	}
251 
252 	private static final class MockDevice implements Device {
253 
254 		private Display display = new Display();
255 
256 		private DeviceDisplay deviceDisplay = new MockDeviceDisplay(display);
257 
258 		private FontManager fontMgr = new MockFontManager();
259 
260 		private Vector softButtons = new Vector();
261 
262 		public void destroy() {
263 
264 		}
265 
266 		public Vector getButtons() {
267 
268 			return null;
269 		}
270 
271 		public DeviceDisplay getDeviceDisplay() {
272 
273 			return this.deviceDisplay;
274 		}
275 
276 		public FontManager getFontManager() {
277 
278 			return this.fontMgr;
279 		}
280 
281 		public InputMethod getInputMethod() {
282 
283 			return null;
284 		}
285 
286 		public UIFactory getUIFactory() {
287 
288 			return null;
289 		}
290 
291 		public String getName() {
292 
293 			return null;
294 		}
295 
296 		public Image getNormalImage() {
297 
298 			return null;
299 		}
300 
301 		public Image getOverImage() {
302 
303 			return null;
304 		}
305 
306 		public Image getPressedImage() {
307 
308 			return null;
309 		}
310 
311 		public Vector getSoftButtons() {
312 
313 			return this.softButtons;
314 		}
315 
316 		public Map getSystemProperties() {
317 
318 			return null;
319 		}
320 
321 		public boolean hasPointerEvents() {
322 
323 			return false;
324 		}
325 
326 		public boolean hasPointerMotionEvents() {
327 
328 			return false;
329 		}
330 
331 		public boolean hasRepeatEvents() {
332 
333 			return false;
334 		}
335 
336 		public void init() {
337 
338 		}
339 
340 		public boolean vibrate(int duration) {
341 
342 			return false;
343 		}
344 
345 		/**
346 		 * @return the display
347 		 */
348 		public final Display getDisplay() {
349 
350 			return display;
351 		}
352 	}
353 
354 	private final MockDevice device = new MockDevice();
355 
356 	private final Display display = device.getDisplay();
357 
358 	protected void setUp() throws Exception {
359 
360 		DeviceFactory.setDevice(this.device);
361 	}
362 
363 	/**
364 	 * According to the spec, callSerially runnables should be called on the
365 	 * event thread after the paints have been serviced. Please see
366 	 * http://archives.java.sun.com/cgi-bin/wa?A2=ind0606&L=kvm-interest&D=0&P=2189
367 	 * for more details
368 	 * 
369 	 * @throws Exception
370 	 */
371 	public void testConcurrency() throws Exception {
372 
373 		MockDisplayable disp = new MockDisplayable();
374 
375 		display.setCurrent(disp);
376 
377 		display.repaint(disp, 0, 0, 10, 10);
378 
379 		assertPrePaintValue(1, disp, 1000);
380 
381 		MockRunner runner = new MockRunner();
382 		display.callSerially(runner);
383 
384 		Thread.sleep(1000);
385 
386 		assertFalse(runner.hasRun);
387 		assertEquals(0, disp.postPaintCount);
388 
389 		synchronized (disp) {
390 
391 			disp.notify();
392 		}
393 
394 		assertEventuallyRun(true, runner, 1000);
395 		assertEquals(1, disp.postPaintCount);
396 	}
397 
398 	/**
399 	 * @param b
400 	 * @param runner
401 	 */
402 	private void assertEventuallyRun(	boolean value,
403 										MockRunner runner,
404 										int timeout) {
405 
406 		long start = System.currentTimeMillis();
407 		while (System.currentTimeMillis() < start + timeout) {
408 
409 			if (value == runner.hasRun)
410 				return;
411 
412 			try {
413 				Thread.sleep(100);
414 			} catch (InterruptedException exception) {
415 
416 				fail("Interrupted");
417 			}
418 		}
419 		assertEquals(value, runner.hasRun);
420 	}
421 
422 	/**
423 	 * @param conditional
424 	 * @param timeout
425 	 */
426 	private final void assertPrePaintValue(	int value,
427 											MockDisplayable disp,
428 											int timeout) {
429 
430 		long start = System.currentTimeMillis();
431 		while (System.currentTimeMillis() < start + timeout) {
432 
433 			if (value == disp.prePaintCount)
434 				return;
435 
436 			try {
437 				Thread.sleep(100);
438 			} catch (InterruptedException exception) {
439 
440 				fail("Interrupted");
441 			}
442 		}
443 		assertEquals(value, disp.prePaintCount);
444 	}
445 }