Home | History | Annotate | Download | only in multimedia
      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.multimedia import display_facade_native
     13 from autotest_lib.client.cros.multimedia import facade_resource
     14 from autotest_lib.client.cros.multimedia.display_info import DisplayInfo
     15 from autotest_lib.client.cros.power import sys_power
     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_id):
     55         """Moves the current window to the indicated display.
     56 
     57         @param display_id: The id of the indicated display.
     58         """
     59         self._display_component.move_to_display(display_id)
     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 capture_calibration_image(self):
    241         """Captures the calibration image.
    242 
    243         @return: An Image object.
    244         """
    245         screenshot_func = self._display_component.save_calibration_image
    246         return self._take_screenshot(screenshot_func)
    247 
    248 
    249     def get_external_resolution(self):
    250         """Gets the resolution of the external screen.
    251 
    252         @return The resolution tuple (width, height) or None if no external
    253                 display is connected.
    254         """
    255         resolution = self._display_component.get_external_resolution()
    256         return tuple(resolution) if resolution else None
    257 
    258 
    259     def get_internal_resolution(self):
    260         """Gets the resolution of the internal screen.
    261 
    262         @return The resolution tuple (width, height) or None if no internal
    263                 display.
    264         """
    265         resolution = self._display_component.get_internal_resolution()
    266         return tuple(resolution) if resolution else None
    267 
    268 
    269     def set_resolution(self, display_id, width, height):
    270         """Sets the resolution on the specified display.
    271 
    272         @param display_id: id of the display to set resolutions for.
    273         @param width: width of the resolution
    274         @param height: height of the resolution
    275         """
    276         self._display_component.set_resolution(display_id, width, height)
    277 
    278 
    279     def get_display_info(self):
    280         """Gets the information of all the displays that are connected to the
    281                 DUT.
    282 
    283         @return: list of object DisplayInfo for display informtion
    284         """
    285         return map(DisplayInfo, self._display_component.get_display_info())
    286 
    287 
    288     def get_display_modes(self, display_id):
    289         """Gets the display modes of the specified display.
    290 
    291         @param display_id: id of the display to get modes from; the id is from
    292             the DisplayInfo list obtained by get_display_info().
    293 
    294         @return: list of DisplayMode dicts.
    295         """
    296         return self._display_component.get_display_modes(display_id)
    297 
    298 
    299     def get_available_resolutions(self, display_id):
    300         """Gets the resolutions from the specified display.
    301 
    302         @param display_id: id of the display to get modes from.
    303 
    304         @return a list of (width, height) tuples.
    305         """
    306         return [tuple(r) for r in
    307                 self._display_component.get_available_resolutions(display_id)]
    308 
    309 
    310     def get_display_rotation(self, display_id):
    311         """Gets the display rotation for the specified display.
    312 
    313         @param display_id: id of the display to get modes from.
    314 
    315         @return: Degree of rotation.
    316         """
    317         return self._display_component.get_display_rotation(display_id)
    318 
    319 
    320     def set_display_rotation(self, display_id, rotation,
    321                              delay_before_rotation=0, delay_after_rotation=0):
    322         """Sets the display rotation for the specified display.
    323 
    324         @param display_id: id of the display to get modes from.
    325         @param rotation: degree of rotation
    326         @param delay_before_rotation: time in second for delay before rotation
    327         @param delay_after_rotation: time in second for delay after rotation
    328         """
    329         self._display_component.set_display_rotation(
    330                 display_id, rotation, delay_before_rotation,
    331                 delay_after_rotation)
    332 
    333 
    334     def get_internal_display_id(self):
    335         """Gets the internal display id.
    336 
    337         @return the id of the internal display.
    338         """
    339         return self._display_component.get_internal_display_id()
    340 
    341 
    342     def get_first_external_display_id(self):
    343         """Gets the first external display id.
    344 
    345         @return the id of the first external display; -1 if not found.
    346         """
    347         return self._display_component.get_first_external_display_id()
    348 
    349 
    350     def reset_connector_if_applicable(self, connector_type):
    351         """Resets Type-C video connector from host end if applicable.
    352 
    353         It's the workaround sequence since sometimes Type-C dongle becomes
    354         corrupted and needs to be re-plugged.
    355 
    356         @param connector_type: A string, like "VGA", "DVI", "HDMI", or "DP".
    357         """
    358         return self._display_component.reset_connector_if_applicable(
    359                 connector_type)
    360