Home | History | Annotate | Download | only in platform_TabletMode
      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 
      5 import logging
      6 import os
      7 import time
      8 
      9 from autotest_lib.client.bin import test, utils
     10 from autotest_lib.client.common_lib import error
     11 from autotest_lib.client.cros.graphics import graphics_utils
     12 from autotest_lib.client.cros.image_comparison import pdiff_image_comparer
     13 
     14 def 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 
     34 class 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