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 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