1 # Copyright 2014 The Chromium OS Authors. All rights reserved. 2 # Use of this source code is governed by a BSD-style license that can be 3 # found in the LICENSE file. 4 5 """An adapter to access the local display facade.""" 6 7 import logging 8 import tempfile 9 from PIL import Image 10 11 from autotest_lib.client.common_lib import error 12 from autotest_lib.client.cros import sys_power 13 from autotest_lib.client.cros.multimedia import display_facade_native 14 from autotest_lib.client.cros.multimedia import facade_resource 15 from autotest_lib.client.cros.multimedia.display_info import DisplayInfo 16 17 18 class DisplayFacadeLocalAdapter(object): 19 """DisplayFacadeLocalAdapter is an adapter to control the local display. 20 21 Methods with non-native-type arguments go to this class and do some 22 conversion; otherwise, go to the DisplayFacadeNative class. 23 """ 24 25 def __init__(self, chrome): 26 """Construct a DisplayFacadeLocalAdapter. 27 28 @param chrome: A Chrome object. 29 """ 30 # Create a DisplayFacadeNative object as a component such that this 31 # class can expose and manipulate its interfaces. 32 self._display_component = display_facade_native.DisplayFacadeNative( 33 facade_resource.FacadeResource(chrome_object=chrome)) 34 35 36 def get_external_connector_name(self): 37 """Gets the name of the external output connector. 38 39 @return The external output connector name as a string; False if nothing 40 is connected. 41 """ 42 return self._display_component.get_external_connector_name() 43 44 45 def get_internal_connector_name(self): 46 """Gets the name of the internal output connector. 47 48 @return The internal output connector name as a string; False if nothing 49 is connected. 50 """ 51 return self._display_component.get_internal_connector_name() 52 53 54 def move_to_display(self, display_index): 55 """Moves the current window to the indicated display. 56 57 @param display_index: The index of the indicated display. 58 """ 59 self._display_component.move_to_display(display_index) 60 61 62 def set_fullscreen(self, is_fullscreen): 63 """Sets the current window to full screen. 64 65 @param is_fullscreen: True or False to indicate fullscreen state. 66 @return True if success, False otherwise. 67 """ 68 return self._display_component.set_fullscreen(is_fullscreen) 69 70 71 def load_url(self, url): 72 """Loads the given url in a new tab. The new tab will be active. 73 74 @param url: The url to load as a string. 75 @return a str, the tab descriptor of the opened tab. 76 """ 77 return self._display_component.load_url(url) 78 79 80 def load_calibration_image(self, resolution): 81 """Load a full screen calibration image from the HTTP server. 82 83 @param resolution: A tuple (width, height) of resolution. 84 @return a str, the tab descriptor of the opened tab. 85 """ 86 return self._display_component.load_calibration_image(resolution) 87 88 89 def load_color_sequence(self, tab_descriptor, color_sequence): 90 """Displays a series of colors on full screen on the tab. 91 tab_descriptor is returned by any open tab API of display facade. 92 e.g., 93 tab_descriptor = load_url('about:blank') 94 load_color_sequence(tab_descriptor, color) 95 96 @param tab_descriptor: Indicate which tab to test. 97 @param color_sequence: An integer list for switching colors. 98 @return A list of the timestamp for each switch. 99 """ 100 return self._display_component.load_color_sequence(tab_descriptor, 101 color_sequence) 102 103 104 def close_tab(self, tab_descriptor): 105 """Disables fullscreen and closes the tab of the given tab descriptor. 106 tab_descriptor is returned by any open tab API of display facade. 107 e.g., 108 1. 109 tab_descriptor = load_url(url) 110 close_tab(tab_descriptor) 111 112 2. 113 tab_descriptor = load_calibration_image(resolution) 114 close_tab(tab_descriptor) 115 116 @param tab_descriptor: Indicate which tab to close. 117 """ 118 self._display_component.close_tab(tab_descriptor) 119 120 121 def is_mirrored_enabled(self): 122 """Checks the mirrored state. 123 124 @return True if mirrored mode is enabled. 125 """ 126 return self._display_component.is_mirrored_enabled() 127 128 129 def set_mirrored(self, is_mirrored): 130 """Sets mirrored mode. 131 132 @param is_mirrored: True or False to indicate mirrored state. 133 @throws error.TestError when the call fails. 134 """ 135 if not self._display_component.set_mirrored(is_mirrored): 136 raise error.TestError('Failed to set_mirrored(%s)' % is_mirrored) 137 138 139 def is_display_primary(self, internal=True): 140 """Checks if internal screen is primary display. 141 142 @param internal: is internal/external screen primary status requested 143 @return boolean True if internal display is primary. 144 """ 145 return self._display_component.is_display_primary(internal) 146 147 148 def suspend_resume(self, suspend_time=10): 149 """Suspends the DUT for a given time in second. 150 151 @param suspend_time: Suspend time in second. 152 """ 153 try: 154 self._display_component.suspend_resume(suspend_time) 155 except sys_power.SpuriousWakeupError as e: 156 # Log suspend/resume errors but continue the test. 157 logging.error('suspend_resume error: %s', str(e)) 158 159 160 def suspend_resume_bg(self, suspend_time=10): 161 """Suspends the DUT for a given time in second in the background. 162 163 @param suspend_time: Suspend time in second, default: 10s. 164 """ 165 self._display_component.suspend_resume_bg(suspend_time) 166 167 168 def wait_external_display_connected(self, display): 169 """Waits for the specified display to be connected. 170 171 @param display: The display name as a string, like 'HDMI1', or 172 False if no external display is expected. 173 @return: True if display is connected; False otherwise. 174 """ 175 return self._display_component.wait_external_display_connected(display) 176 177 178 def hide_cursor(self): 179 """Hides mouse cursor by sending a keystroke.""" 180 self._display_component.hide_cursor() 181 182 183 def hide_typing_cursor(self): 184 """Hides typing cursor by moving outside typing bar.""" 185 self._display_component.hide_typing_cursor() 186 187 188 def set_content_protection(self, state): 189 """Sets the content protection of the external screen. 190 191 @param state: One of the states 'Undesired', 'Desired', or 'Enabled' 192 """ 193 self._display_component.set_content_protection(state) 194 195 196 def get_content_protection(self): 197 """Gets the state of the content protection. 198 199 @param output: The output name as a string. 200 @return: A string of the state, like 'Undesired', 'Desired', or 'Enabled'. 201 False if not supported. 202 """ 203 return self._display_component.get_content_protection() 204 205 206 def _take_screenshot(self, screenshot_func): 207 """Gets screenshot from frame buffer. 208 209 @param screenshot_func: function to take a screenshot and save the image 210 to specified path. Usage: screenshot_func(path). 211 212 @return: An Image object. 213 Notice that the returned image may not be in RGB format, 214 depending on PIL implementation. 215 """ 216 with tempfile.NamedTemporaryFile(suffix='.png') as f: 217 screenshot_func(f.name) 218 return Image.open(f.name) 219 220 221 def capture_internal_screen(self): 222 """Captures the internal screen framebuffer. 223 224 @return: An Image object. 225 """ 226 screenshot_func = self._display_component.take_internal_screenshot 227 return self._take_screenshot(screenshot_func) 228 229 230 # TODO(ihf): This function needs to be fixed for multiple screens. 231 def capture_external_screen(self): 232 """Captures the external screen framebuffer. 233 234 @return: An Image object. 235 """ 236 screenshot_func = self._display_component.take_external_screenshot 237 return self._take_screenshot(screenshot_func) 238 239 240 def get_external_resolution(self): 241 """Gets the resolution of the external screen. 242 243 @return The resolution tuple (width, height) or None if no external 244 display is connected. 245 """ 246 resolution = self._display_component.get_external_resolution() 247 return tuple(resolution) if resolution else None 248 249 250 def get_internal_resolution(self): 251 """Gets the resolution of the internal screen. 252 253 @return The resolution tuple (width, height) or None if no internal 254 display. 255 """ 256 resolution = self._display_component.get_internal_resolution() 257 return tuple(resolution) if resolution else None 258 259 260 def set_resolution(self, display_index, width, height): 261 """Sets the resolution on the specified display. 262 263 @param display_index: index of the display to set resolutions for. 264 @param width: width of the resolution 265 @param height: height of the resolution 266 """ 267 self._display_component.set_resolution(display_index, width, height) 268 269 270 def get_display_info(self): 271 """Gets the information of all the displays that are connected to the 272 DUT. 273 274 @return: list of object DisplayInfo for display informtion 275 """ 276 return map(DisplayInfo, self._display_component.get_display_info()) 277 278 279 def get_display_modes(self, display_index): 280 """Gets the display modes of the specified display. 281 282 @param display_index: index of the display to get modes from; the index 283 is from the DisplayInfo list obtained by get_display_info(). 284 285 @return: list of DisplayMode dicts. 286 """ 287 return self._display_component.get_display_modes(display_index) 288 289 290 def get_available_resolutions(self, display_index): 291 """Gets the resolutions from the specified display. 292 293 @param display_index: index of the display to get modes from. 294 295 @return a list of (width, height) tuples. 296 """ 297 return [tuple(r) for r in 298 self._display_component.get_available_resolutions( 299 display_index)] 300 301 302 def get_display_rotation(self, display_index): 303 """Gets the display rotation for the specified display. 304 305 @param display_index: index of the display to get modes from. 306 307 @return: Degree of rotation. 308 """ 309 return self._display_component.get_display_rotation(display_index) 310 311 312 def set_display_rotation(self, display_index, rotation, 313 delay_before_rotation=0, delay_after_rotation=0): 314 """Sets the display rotation for the specified display. 315 316 @param display_index: index of the display to get modes from. 317 @param rotation: degree of rotation 318 @param delay_before_rotation: time in second for delay before rotation 319 @param delay_after_rotation: time in second for delay after rotation 320 """ 321 self._display_component.set_display_rotation( 322 display_index, rotation, delay_before_rotation, 323 delay_after_rotation) 324 325 326 def get_first_external_display_index(self): 327 """Gets the first external display index. 328 329 @return the index of the first external display; False if not found. 330 """ 331 return self._display_component.get_first_external_display_index() 332 333 334 def reset_connector_if_applicable(self, connector_type): 335 """Resets video connector from host end if applicable. 336 337 This is the workaround method for remote display facade adapter only. 338 Put an empty method here in local adapter to prevent AttributeError of 339 client test. 340 341 @param connector_type: A string, like "VGA", "DVI", "HDMI", or "DP". 342 """ 343 pass 344