普通文本  |  178行  |  7.79 KB

# Copyright 2014 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import logging
import time

from autotest_lib.client.bin import utils
from autotest_lib.client.cros.chameleon import screen_utility_factory


class ChameleonScreenTest(object):
    """Utility to test the screen between Chameleon and CrOS.

    This class contains the screen-related testing operations.

    """
    # Time in seconds to wait for notation bubbles, including bubbles for
    # external detection, mirror mode and fullscreen, to disappear.
    _TEST_IMAGE_STABILIZE_TIME = 10

    def __init__(self, chameleon_port, display_facade, output_dir):
        """Initializes the ScreenUtilityFactory objects."""
        self._display_facade = display_facade
        factory = screen_utility_factory.ScreenUtilityFactory(
                chameleon_port, display_facade)
        self._resolution_comparer = factory.create_resolution_comparer()
        self._screen_comparer = factory.create_screen_comparer(output_dir)
        self._mirror_comparer = factory.create_mirror_comparer(output_dir)
        self._calibration_image_tab_descriptor = None


    def test_resolution(self, expected_resolution):
        """Tests if the resolution of Chameleon matches with the one of CrOS.

        @param expected_resolution: A tuple (width, height) for the expected
                                    resolution.
        @return: None if the check passes; otherwise, a string of error message.
        """
        return self._resolution_comparer.compare(expected_resolution)


    def test_screen(self, expected_resolution, test_mirrored=None,
                    error_list=None):
        """Tests if the screen of Chameleon matches with the one of CrOS.

        @param expected_resolution: A tuple (width, height) for the expected
                                    resolution.
        @param test_mirrored: True to test mirrored mode. False not to. None
                              to test mirrored mode iff the current mode is
                              mirrored.
        @param error_list: A list to append the error message to or None.
        @return: None if the check passes; otherwise, a string of error message.
        """
        if test_mirrored is None:
            test_mirrored = self._display_facade.is_mirrored_enabled()

        error = self._resolution_comparer.compare(expected_resolution)
        if not error:
            # Do two screen comparisons with and without hiding cursor, to
            # work-around some devices still showing cursor on CrOS FB.
            # TODO: Remove this work-around once crosbug/p/34524 got fixed.
            error = self._screen_comparer.compare()
            if error:
                logging.info('Hide cursor and do screen comparison again...')
                self._display_facade.hide_cursor()
                error = self._screen_comparer.compare()
        if not error and test_mirrored:
            error = self._mirror_comparer.compare()
        if error and error_list is not None:
            error_list.append(error)
        return error


    def load_test_image(self, image_size, test_mirrored=None):
        """Loads calibration image on the CrOS with logging

        @param image_size: A tuple (width, height) conforms the resolution.
        @param test_mirrored: True to test mirrored mode. False not to. None
                              to test mirrored mode iff the current mode is
                              mirrored.
        """
        if test_mirrored is None:
            test_mirrored = self._display_facade.is_mirrored_enabled()
        self._calibration_image_tab_descriptor = \
            self._display_facade.load_calibration_image(image_size)
        if not test_mirrored:
            self._display_facade.move_to_display(
                    self._display_facade.get_first_external_display_index())
        self._display_facade.set_fullscreen(True)
        logging.info('Waiting for calibration image to stabilize...')
        time.sleep(self._TEST_IMAGE_STABILIZE_TIME)


    def unload_test_image(self):
        """Closes the tab in browser to unload the fullscreen test image."""
        self._display_facade.close_tab(self._calibration_image_tab_descriptor)


    def test_screen_with_image(self, expected_resolution, test_mirrored=None,
                               error_list=None, chameleon_supported=True,
                               retry_count=2):
        """Tests the screen with image loaded.

        @param expected_resolution: A tuple (width, height) for the expected
                                    resolution.
        @param test_mirrored: True to test mirrored mode. False not to. None
                              to test mirrored mode iff the current mode is
                              mirrored.
        @param error_list: A list to append the error message to or None.
        @param retry_count: A count to retry the screen test.
        @param chameleon_supported: Whether resolution is supported by
                                    chameleon. The DP RX doesn't support
                                    4K resolution. The max supported resolution
                                    is 2560x1600. See crbug/585900.
        @return: None if the check passes; otherwise, a string of error message.
        """
        if test_mirrored is None:
            test_mirrored = self._display_facade.is_mirrored_enabled()

        if test_mirrored:
            test_image_size = self._display_facade.get_internal_resolution()
        else:
            # DUT needs time to respond to the plug event
            test_image_size = utils.wait_for_value_changed(
                    self._display_facade.get_external_resolution,
                    old_value=None)
        error = None
        if test_image_size != expected_resolution:
            error = ('Screen size %s is not as expected %s!'
                     % (str(test_image_size), str(expected_resolution)))
            if test_mirrored:
                # For the case of mirroring, depending on hardware vs
                # software mirroring, screen size can be different.
                logging.info('Warning: %s', error)
                error = None
            else:
                error_list.append(error)

        if chameleon_supported:
            error = self._resolution_comparer.compare(expected_resolution)
            if not error:
                while retry_count:
                    retry_count = retry_count - 1
                    try:
                        self.load_test_image(test_image_size)
                        error = self.test_screen(expected_resolution, test_mirrored)
                        if error is None:
                            return error
                        elif retry_count > 0:
                            logging.info('Retry screen comparison again...')
                    finally:
                        self.unload_test_image()

            if error and error_list is not None:
                error_list.append(error)
        return error


    def check_external_display_connected(self, expected_display,
                                         error_list=None):
        """Checks the given external display connected.

        @param expected_display: Name of the expected display or False
                if no external display is expected.
        @param error_list: A list to append the error message to or None.
        @return: None if the check passes; otherwise, a string of error message.
        """
        error = None
        if not self._display_facade.wait_external_display_connected(
                expected_display):
            error = 'Waited for display %s but timed out' % expected_display

        if error and error_list is not None:
            logging.error(error)
            error_list.append(error)
        return error