• 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 PNG format.
74
75        @param suffixcurrent_vt: desired vt for screenshot.
76
77        @returns the path of the screenshot file.
78
79        """
80        return graphics_utils.take_screenshot(self.resultsdir,
81                                              suffix + '_tablet_mode')
82
83    def _verify_difference(self, screenshot1, screenshot2,
84                           difference_percent_threshold=5):
85        """
86        Make sure screenshots are sufficiently different.
87
88        @param screenshot1: path to screenshot.
89        @param screenshot2: path to screenshot.
90        @param difference_percent_threshold: threshold for difference.
91
92        @returns number of errors found (0 or 1).
93
94        """
95        filename1 = screenshot1.split('/')[-1]
96        filename2 = screenshot2.split('/')[-1]
97        diff = get_percent_difference(screenshot1, screenshot2)
98        logging.info("Screenshot 1 and 2 diff: %s" % diff)
99        if not diff >= difference_percent_threshold:
100            error = ('Screenshots differ by %d %%: %s vs %s'
101                     % (diff, filename1, filename2))
102            self.ERRORS.append(error)
103
104    def _verify_similarity(self, screenshot1, screenshot2,
105                           similarity_percent_threshold=5):
106        """
107        Make sure screenshots are the same or similar.
108
109        @param screenshot1: path to screenshot.
110        @param screenshot2: path to screenshot.
111        @param difference_percent_threshold: threshold for similarity.
112
113        @returns number of errors found (0 or 1).
114
115        """
116        filename1 = screenshot1.split('/')[-1]
117        filename2 = screenshot2.split('/')[-1]
118        diff = get_percent_difference(screenshot1, screenshot2)
119        logging.info("Screenshot 1 and 2 similarity diff: %s" % diff)
120        if not diff <= similarity_percent_threshold:
121            error = ('Screenshots differ by %d %%: %s vs %s'
122                     % (diff, filename1, filename2))
123            self.ERRORS.append(error)
124
125    def run_once(self):
126        """
127        Run tablet mode test to spoof various tablet modes and ensure
128        device changes accordingly.
129        """
130
131        # Ensure we start in laptop mode.
132        self._revert_laptop()
133
134        logging.info("Take screenshot for initial laptop mode.")
135        laptop_start = self._take_screenshot('laptop_start')
136
137        logging.info("Entering landscape mode.")
138        self._spoof_tablet_landscape()
139        landscape = self._take_screenshot('landscape')
140
141        self._revert_laptop()
142
143        logging.info("Entering portrait mode.")
144        self._spoof_tablet_portrait()
145        portrait = self._take_screenshot('portrait')
146
147        self._revert_laptop()
148        laptop_end = self._take_screenshot('laptop_end')
149
150        # Compare screenshots and determine the number of errors.
151        self._verify_similarity(laptop_start, laptop_end)
152        self._verify_difference(laptop_start, landscape)
153        self._verify_difference(landscape, portrait)
154        self._verify_difference(portrait, laptop_end)
155
156        if self.ERRORS:
157            raise error.TestFail('; '.join(set(self.ERRORS)))
158
159    def cleanup(self):
160        self._revert_laptop()
161