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