• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2017 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
5import logging
6import os
7import time
8
9from autotest_lib.client.bin import test, utils
10from autotest_lib.client.common_lib import error
11from autotest_lib.client.cros.graphics import graphics_utils
12from autotest_lib.client.cros.image_comparison import pdiff_image_comparer
13
14def get_percent_difference(file1, file2):
15    """
16    Performs pixel comparison of two files, given by their paths |file1|
17    and |file2| using terminal tool 'perceptualdiff' and returns percentage
18    difference of the total file size.
19
20    @param file1: path to image
21    @param file2: path to secondary image
22    @return: percentage difference of total file size.
23    @raise ValueError: if image dimensions are not the same
24    @raise OSError: if file does not exist or cannot be opened.
25
26    """
27    # Using pdiff image comparer to compare the two images. This class
28    # invokes the terminal tool perceptualdiff.
29    pdi = pdiff_image_comparer.PdiffImageComparer()
30    diff_bytes = pdi.compare(file1, file2)[0]
31    return round(100. * diff_bytes / os.path.getsize(file1))
32
33
34class platform_TabletMode(test.test):
35    """
36    Verify that tablet mode toggles appropriately.
37    """
38    version = 1
39    _WAIT = 5
40    _SHORT_WAIT = 1
41    SPOOF_CMD = 'ectool motionsense spoof '
42    # Disable spoof mode and return into laptop state.
43    RESET_SENSOR_0 = '-- 0 0'
44    RESET_SENSOR_1 = '-- 1 0'
45    # Spoof sensor 1 to force laptop into landscape tablet mode.
46    LANDSCAPE_SENSOR_1 = '-- 1 1 32 -16256 -224'
47    # Spoof sensor 0 and sensor 1 to force laptop into portrait tablet mode.
48    PORTRAIT_SENSOR_0 = '-- 0 1 -7760 -864 -14112'
49    PORTRAIT_SENSOR_1 = '-- 1 1 -7936 848 14480'
50    ERRORS = []
51
52    def _revert_laptop(self):
53        """Resets sensors to revert back to laptop mode."""
54        utils.system(self.SPOOF_CMD + self.RESET_SENSOR_0)
55        time.sleep(self._SHORT_WAIT)
56        utils.system(self.SPOOF_CMD + self.RESET_SENSOR_1)
57        time.sleep(self._WAIT)
58
59    def _spoof_tablet_landscape(self):
60        """Spoofs sensors to change into tablet landscape mode."""
61        utils.system(self.SPOOF_CMD + self.LANDSCAPE_SENSOR_1)
62        time.sleep(self._WAIT)
63
64    def _spoof_tablet_portrait(self):
65        """Spoofs sensors to change into tablet portrait mode."""
66        utils.system(self.SPOOF_CMD + self.PORTRAIT_SENSOR_0)
67        time.sleep(self._SHORT_WAIT)
68        utils.system(self.SPOOF_CMD + self.PORTRAIT_SENSOR_1)
69        time.sleep(self._WAIT)
70
71    def _take_screenshot(self, suffix):
72        """
73        Captures a screenshot of the current VT screen in BMP format.
74
75        @param suffixcurrent_vt: desired vt for screenshot.
76
77        @returns the path of the screenshot file.
78
79        """
80        extension = 'bmp'
81        return graphics_utils.take_screenshot(self.resultsdir,
82                                              suffix + '_tablet_mode',
83                                              extension)
84
85    def _verify_difference(self, screenshot1, screenshot2,
86                           difference_percent_threshold=5):
87        """
88        Make sure screenshots are sufficiently different.
89
90        @param screenshot1: path to screenshot.
91        @param screenshot2: path to screenshot.
92        @param difference_percent_threshold: threshold for difference.
93
94        @returns number of errors found (0 or 1).
95
96        """
97        filename1 = screenshot1.split('/')[-1]
98        filename2 = screenshot2.split('/')[-1]
99        diff = get_percent_difference(screenshot1, screenshot2)
100        logging.info("Screenshot 1 and 2 diff: %s" % diff)
101        if not diff >= difference_percent_threshold:
102            error = ('Screenshots differ by %d %%: %s vs %s'
103                     % (diff, filename1, filename2))
104            self.ERRORS.append(error)
105
106    def _verify_similarity(self, screenshot1, screenshot2,
107                           similarity_percent_threshold=5):
108        """
109        Make sure screenshots are the same or similar.
110
111        @param screenshot1: path to screenshot.
112        @param screenshot2: path to screenshot.
113        @param difference_percent_threshold: threshold for similarity.
114
115        @returns number of errors found (0 or 1).
116
117        """
118        filename1 = screenshot1.split('/')[-1]
119        filename2 = screenshot2.split('/')[-1]
120        diff = get_percent_difference(screenshot1, screenshot2)
121        logging.info("Screenshot 1 and 2 similarity diff: %s" % diff)
122        if not diff <= similarity_percent_threshold:
123            error = ('Screenshots differ by %d %%: %s vs %s'
124                     % (diff, filename1, filename2))
125            self.ERRORS.append(error)
126
127    def run_once(self):
128        """
129        Run tablet mode test to spoof various tablet modes and ensure
130        device changes accordingly.
131        """
132
133        # Ensure we start in laptop mode.
134        self._revert_laptop()
135
136        logging.info("Take screenshot for initial laptop mode.")
137        laptop_start = self._take_screenshot('laptop_start')
138
139        logging.info("Entering landscape mode.")
140        self._spoof_tablet_landscape()
141        landscape = self._take_screenshot('landscape')
142
143        self._revert_laptop()
144
145        logging.info("Entering portrait mode.")
146        self._spoof_tablet_portrait()
147        portrait = self._take_screenshot('portrait')
148
149        self._revert_laptop()
150        laptop_end = self._take_screenshot('laptop_end')
151
152        # Compare screenshots and determine the number of errors.
153        self._verify_similarity(laptop_start, laptop_end)
154        self._verify_difference(laptop_start, landscape)
155        self._verify_difference(landscape, portrait)
156        self._verify_difference(portrait, laptop_end)
157
158        if self.ERRORS:
159            raise error.TestFail('; '.join(set(self.ERRORS)))
160
161    def cleanup(self):
162        self._revert_laptop()
163