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