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