Home | History | Annotate | Download | only in chameleon
      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 import logging
      6 import time
      7 
      8 from autotest_lib.client.bin import utils
      9 from autotest_lib.client.cros.chameleon import screen_utility_factory
     10 
     11 
     12 class ChameleonScreenTest(object):
     13     """Utility to test the screen between Chameleon and CrOS.
     14 
     15     This class contains the screen-related testing operations.
     16 
     17     """
     18     # Time in seconds to wait for notation bubbles, including bubbles for
     19     # external detection, mirror mode and fullscreen, to disappear.
     20     _TEST_IMAGE_STABILIZE_TIME = 10
     21 
     22     def __init__(self, chameleon_port, display_facade, output_dir):
     23         """Initializes the ScreenUtilityFactory objects."""
     24         self._display_facade = display_facade
     25         factory = screen_utility_factory.ScreenUtilityFactory(
     26                 chameleon_port, display_facade)
     27         self._resolution_comparer = factory.create_resolution_comparer()
     28         self._screen_comparer = factory.create_screen_comparer(output_dir)
     29         self._mirror_comparer = factory.create_mirror_comparer(output_dir)
     30         self._calibration_image_tab_descriptor = None
     31 
     32 
     33     def test_resolution(self, expected_resolution):
     34         """Tests if the resolution of Chameleon matches with the one of CrOS.
     35 
     36         @param expected_resolution: A tuple (width, height) for the expected
     37                                     resolution.
     38         @return: None if the check passes; otherwise, a string of error message.
     39         """
     40         return self._resolution_comparer.compare(expected_resolution)
     41 
     42 
     43     def test_screen(self, expected_resolution, test_mirrored=None,
     44                     error_list=None):
     45         """Tests if the screen of Chameleon matches with the one of CrOS.
     46 
     47         @param expected_resolution: A tuple (width, height) for the expected
     48                                     resolution.
     49         @param test_mirrored: True to test mirrored mode. False not to. None
     50                               to test mirrored mode iff the current mode is
     51                               mirrored.
     52         @param error_list: A list to append the error message to or None.
     53         @return: None if the check passes; otherwise, a string of error message.
     54         """
     55         if test_mirrored is None:
     56             test_mirrored = self._display_facade.is_mirrored_enabled()
     57 
     58         error = self._resolution_comparer.compare(expected_resolution)
     59         if not error:
     60             # Do two screen comparisons with and without hiding cursor, to
     61             # work-around some devices still showing cursor on CrOS FB.
     62             # TODO: Remove this work-around once crosbug/p/34524 got fixed.
     63             error = self._screen_comparer.compare()
     64             if error:
     65                 logging.info('Hide cursor and do screen comparison again...')
     66                 self._display_facade.hide_cursor()
     67                 error = self._screen_comparer.compare()
     68         if not error and test_mirrored:
     69             error = self._mirror_comparer.compare()
     70         if error and error_list is not None:
     71             error_list.append(error)
     72         return error
     73 
     74 
     75     def load_test_image(self, image_size, test_mirrored=None):
     76         """Loads calibration image on the CrOS with logging
     77 
     78         @param image_size: A tuple (width, height) conforms the resolution.
     79         @param test_mirrored: True to test mirrored mode. False not to. None
     80                               to test mirrored mode iff the current mode is
     81                               mirrored.
     82         """
     83         if test_mirrored is None:
     84             test_mirrored = self._display_facade.is_mirrored_enabled()
     85         self._calibration_image_tab_descriptor = \
     86             self._display_facade.load_calibration_image(image_size)
     87         if not test_mirrored:
     88             self._display_facade.move_to_display(
     89                     self._display_facade.get_first_external_display_index())
     90         self._display_facade.set_fullscreen(True)
     91         logging.info('Waiting for calibration image to stabilize...')
     92         time.sleep(self._TEST_IMAGE_STABILIZE_TIME)
     93 
     94 
     95     def unload_test_image(self):
     96         """Closes the tab in browser to unload the fullscreen test image."""
     97         self._display_facade.close_tab(self._calibration_image_tab_descriptor)
     98 
     99 
    100     def test_screen_with_image(self, expected_resolution, test_mirrored=None,
    101                                error_list=None, retry_count=2):
    102         """Tests the screen with image loaded.
    103 
    104         @param expected_resolution: A tuple (width, height) for the expected
    105                                     resolution.
    106         @param test_mirrored: True to test mirrored mode. False not to. None
    107                               to test mirrored mode iff the current mode is
    108                               mirrored.
    109         @param error_list: A list to append the error message to or None.
    110         @param retry_count: A count to retry the screen test.
    111         @return: None if the check passes; otherwise, a string of error message.
    112         """
    113         if test_mirrored is None:
    114             test_mirrored = self._display_facade.is_mirrored_enabled()
    115 
    116         if test_mirrored:
    117             test_image_size = self._display_facade.get_internal_resolution()
    118         else:
    119             # DUT needs time to respond to the plug event
    120             test_image_size = utils.wait_for_value_changed(
    121                     self._display_facade.get_external_resolution,
    122                     old_value=None)
    123 
    124         error = self._resolution_comparer.compare(expected_resolution)
    125         if not error:
    126             while retry_count:
    127                 retry_count = retry_count - 1
    128                 try:
    129                     self.load_test_image(test_image_size)
    130                     error = self.test_screen(expected_resolution, test_mirrored)
    131                     if error is None:
    132                         return error
    133                     elif retry_count > 0:
    134                         logging.info('Retry screen comparison again...')
    135                 finally:
    136                     self.unload_test_image()
    137 
    138         if error and error_list is not None:
    139             error_list.append(error)
    140         return error
    141 
    142 
    143     def check_external_display_connected(self, expected_display,
    144                                          error_list=None):
    145         """Checks the given external display connected.
    146 
    147         @param expected_display: Name of the expected display or False
    148                 if no external display is expected.
    149         @param error_list: A list to append the error message to or None.
    150         @return: None if the check passes; otherwise, a string of error message.
    151         """
    152         error = None
    153         if not self._display_facade.wait_external_display_connected(
    154                 expected_display):
    155             error = 'Waited for display %s but timed out' % expected_display
    156 
    157         if error and error_list is not None:
    158             logging.error(error)
    159             error_list.append(error)
    160         return error
    161