OLD | NEW |
| (Empty) |
1 #!/usr/bin/python | |
2 # | |
3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | |
4 # Use of this source code is governed by a BSD-style license that can be | |
5 # found in the LICENSE file. | |
6 | |
7 # DESCRIPTION : | |
8 # | |
9 # Intended for use during manufacturing to validate that all touchpad | |
10 # features function properly. Run normally, this program will display a | |
11 # touchpad image and buttons will be highlighted as they are pressed and | |
12 # released. Once all functions have been used, a brief 'PASS' message will | |
13 # be displayed and the test will terminate. After the first button is | |
14 # hit, a countdown will begin. If not all buttons are used in time, the | |
15 # test will fail with an 'ERROR' message that is displayed forever. | |
16 | |
17 import cairo | |
18 import gobject | |
19 import gtk | |
20 import os | |
21 import sys | |
22 import time | |
23 | |
24 class Button: | |
25 def __init__(self, coords): | |
26 self._pressed = False | |
27 self._released = False | |
28 self._coords = coords | |
29 | |
30 class TouchpadTest: | |
31 # Coordinates of buttons we need to highlight. | |
32 left_button_coords = (65, 321, 255, 93) | |
33 right_button_coords = (321, 321, 254, 93) | |
34 | |
35 # How long TouchpadTest allows in seconds from the first move or button | |
36 # pressed until defaulting to the failure condition. | |
37 timeout = 50 | |
38 | |
39 # How long to display the success message in seconds before exit. | |
40 pass_msg_timeout = 2 | |
41 | |
42 # Background color and alpha for the final result message. | |
43 bg_rgba_error = (0.7, 0, 0, 0.9) | |
44 bg_rgba_pass = ( 0, 0.7, 0, 0.9) | |
45 | |
46 # Highlight color and alpha to indicate activated keys. | |
47 rgba_press_and_release = ( 0, 0.5, 0, 0.6) | |
48 rgba_press_only = (0.6, 0.6, 0, 0.6) | |
49 | |
50 def __init__(self, image, exit_on_error=False): | |
51 self._image = image | |
52 self._exit_on_error = exit_on_error | |
53 self._deadline = None | |
54 self._success = None | |
55 self._buttons = {} | |
56 self._buttons[1] = Button(TouchpadTest.left_button_coords) | |
57 self._buttons[3] = Button(TouchpadTest.right_button_coords) | |
58 | |
59 def has_test_passed(self): | |
60 for key in self._buttons.keys(): | |
61 if (not self._buttons[key]._pressed or | |
62 not self._buttons[key]._released): | |
63 return False | |
64 return True | |
65 | |
66 def show_result(self, widget, context, text, bg_rgba): | |
67 widget_width, widget_height = widget.get_size_request() | |
68 context.save() | |
69 context.scale(widget_width / 1.0, widget_height / 1.0) | |
70 context.rectangle(0.05, 0.05, 0.9, 0.9) | |
71 context.set_source_rgba(*bg_rgba) | |
72 context.fill() | |
73 context.set_source_rgba(0.1, 0.1, 0.1, 0.95) | |
74 context.select_font_face( | |
75 'Verdana', cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) | |
76 context.set_font_size(0.2) | |
77 x_bearing, y_bearing, width, height = context.text_extents(text)[:4] | |
78 context.move_to(0.5 - (width / 2) - x_bearing, | |
79 0.5 - (height / 2) - y_bearing) | |
80 context.show_text(text) | |
81 context.restore() | |
82 | |
83 def start_countdown(self, duration): | |
84 self._deadline = int(time.time()) + duration | |
85 | |
86 def show_countdown(self, widget, context): | |
87 countdown = self._deadline - int(time.time()) | |
88 width, height = widget.get_size_request() | |
89 text = '%3d' % countdown | |
90 context.save() | |
91 context.translate(width - 60, height) | |
92 context.set_source_rgb(0.5, 0.5, 0.5) | |
93 context.select_font_face( | |
94 'Courier New', cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD) | |
95 context.set_font_size(20) | |
96 x_bearing, y_bearing = context.text_extents('000')[:2] | |
97 context.move_to(x_bearing, y_bearing) | |
98 context.show_text(text) | |
99 context.restore() | |
100 | |
101 def timer_event(self, window): | |
102 if not self._deadline: | |
103 # Ignore timer events with no countdown in progress. | |
104 return True | |
105 if self._deadline <= time.time(): | |
106 self._deadline = None | |
107 if self._success is None: | |
108 self._success = False | |
109 if self._exit_on_error: | |
110 sys.exit(1) | |
111 elif self._success: | |
112 sys.exit(0) | |
113 window.queue_draw() | |
114 return True | |
115 | |
116 def expose_event(self, widget, event): | |
117 context = widget.window.cairo_create() | |
118 | |
119 # Show touchpad image as the background. | |
120 context.set_source_surface(self._image, 0, 0) | |
121 context.paint() | |
122 | |
123 # Boolean values for success correspond with test pass or | |
124 # failure. None means normal operation. | |
125 if self._success is None: | |
126 for key in self._buttons.keys(): | |
127 color = None | |
128 if self._buttons[key]._released: | |
129 color = TouchpadTest.rgba_press_and_release | |
130 elif self._buttons[key]._pressed: | |
131 color = TouchpadTest.rgba_press_only | |
132 else: | |
133 continue | |
134 coords = self._buttons[key]._coords | |
135 context.rectangle(*coords) | |
136 context.set_source_rgba(*color) | |
137 context.fill() | |
138 if self._deadline: | |
139 self.show_countdown(widget, context) | |
140 elif self._success: | |
141 self.show_result(widget, context, 'PASS', | |
142 TouchpadTest.bg_rgba_pass) | |
143 else: | |
144 self.show_result(widget, context, 'ERROR', | |
145 TouchpadTest.bg_rgba_error) | |
146 return False | |
147 | |
148 def button_press_event(self, widget, event): | |
149 if self._success is not None: | |
150 return True | |
151 if not event.button in self._buttons.keys(): | |
152 return True | |
153 | |
154 if self._deadline is None: | |
155 self.start_countdown(TouchpadTest.timeout) | |
156 self._buttons[event.button]._pressed = True | |
157 widget.queue_draw() | |
158 return True | |
159 | |
160 def button_release_event(self, widget, event): | |
161 if self._success is not None: | |
162 return True | |
163 if not event.button in self._buttons.keys(): | |
164 return True | |
165 | |
166 self._buttons[event.button]._released = True | |
167 if self.has_test_passed(): | |
168 self._success = True | |
169 self.start_countdown(TouchpadTest.pass_msg_timeout) | |
170 widget.queue_draw() | |
171 return True | |
172 | |
173 def main(): | |
174 window = gtk.Window(gtk.WINDOW_TOPLEVEL) | |
175 window.set_name('Touchpad Test') | |
176 window.connect('destroy', lambda w: gtk.main_quit()) | |
177 | |
178 bg_color = gtk.gdk.color_parse('midnight blue') | |
179 window.modify_bg(gtk.STATE_NORMAL, bg_color) | |
180 | |
181 touchpad_image = cairo.ImageSurface.create_from_png('touchpad.png') | |
182 touchpad_image_size = (touchpad_image.get_width(), | |
183 touchpad_image.get_height()) | |
184 | |
185 drawing_area = gtk.DrawingArea() | |
186 drawing_area.set_size_request(*touchpad_image_size) | |
187 | |
188 exit_on_error = False | |
189 if '--exit-on-error' in sys.argv: | |
190 exit_on_error = True | |
191 tt = TouchpadTest(touchpad_image, exit_on_error=exit_on_error) | |
192 screen = window.get_screen() | |
193 screen_size = (screen.get_width(), screen.get_height()) | |
194 window.set_default_size(*screen_size) | |
195 window.connect('button_press_event', tt.button_press_event) | |
196 window.connect('button_release_event', tt.button_release_event) | |
197 gobject.timeout_add(1000, tt.timer_event, window) | |
198 | |
199 drawing_area.connect('expose_event', tt.expose_event) | |
200 | |
201 drawing_area.show() | |
202 | |
203 align = gtk.Alignment(xalign=0.5, yalign=0.5) | |
204 align.add(drawing_area) | |
205 align.show() | |
206 | |
207 drawing_area.set_events(gtk.gdk.EXPOSURE_MASK | | |
208 gtk.gdk.BUTTON_PRESS_MASK | | |
209 gtk.gdk.BUTTON_RELEASE_MASK) | |
210 | |
211 window.add(align) | |
212 window.show() | |
213 | |
214 gtk.main() | |
215 | |
216 return (tt._success != True) | |
217 | |
218 if __name__ == '__main__': | |
219 main() | |
OLD | NEW |