1# Copyright 2020 The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15 16import logging 17import time 18 19from mobly import asserts 20from mobly import base_test 21from mobly import utils 22from mobly.controllers import android_device 23 24import its_session_utils 25 26ADAPTIVE_BRIGHTNESS_OFF = '0' 27TABLET_CMD_DELAY_SEC = 0.5 # found empirically 28TABLET_DIMMER_TIMEOUT_MS = 1800000 # this is max setting possible 29CTS_VERIFIER_PKG = 'com.android.cts.verifier' 30WAIT_TIME_SEC = 5 31SCROLLER_TIMEOUT_MS = 3000 32VALID_NUM_DEVICES = (1, 2) 33NOT_YET_MANDATED_ALL = 100 34 35# Not yet mandated tests ['test', first_api_level mandatory] 36# ie. ['test_test_patterns', 30] is MANDATED for first_api_level >= 30 37NOT_YET_MANDATED = { 38 'scene0': [['test_test_patterns', 30], 39 ['test_tonemap_curve', 30]], 40 'scene1_1': [['test_ae_precapture_trigger', 28], 41 ['test_channel_saturation', 29]], 42 'scene1_2': [], 43 'scene2_a': [['test_jpeg_quality', 30]], 44 'scene2_b': [['test_auto_per_frame_control', NOT_YET_MANDATED_ALL]], 45 'scene2_c': [], 46 'scene2_d': [['test_num_faces', 30]], 47 'scene2_e': [['test_num_faces', 30], ['test_continuous_picture', 30]], 48 'scene3': [], 49 'scene4': [], 50 'scene5': [], 51 'scene6': [['test_zoom', 30]], 52 'sensor_fusion': [], 53 'scene_change': [['test_scene_change', 31]] 54} 55 56 57class ItsBaseTest(base_test.BaseTestClass): 58 """Base test for CameraITS tests. 59 60 Tests inherit from this class execute in the Camera ITS automation systems. 61 These systems consist of either: 62 1. a device under test (dut) and an external rotation controller 63 2. a device under test (dut) and one screen device(tablet) 64 3. a device under test (dut) and manual charts 65 66 Attributes: 67 dut: android_device.AndroidDevice, the device under test. 68 tablet: android_device.AndroidDevice, the tablet device used to display 69 scenes. 70 """ 71 72 def setup_class(self): 73 devices = self.register_controller(android_device, min_number=1) 74 self.dut = devices[0] 75 self.camera = str(self.user_params['camera']) 76 logging.debug('Camera_id: %s', self.camera) 77 if self.user_params.get('chart_distance'): 78 self.chart_distance = float(self.user_params['chart_distance']) 79 logging.debug('Chart distance: %s cm', self.chart_distance) 80 if self.user_params.get('chart_loc_arg'): 81 self.chart_loc_arg = self.user_params['chart_loc_arg'] 82 else: 83 self.chart_loc_arg = '' 84 if self.user_params.get('debug_mode'): 85 self.debug_mode = True if self.user_params[ 86 'debug_mode'] == 'True' else False 87 if self.user_params.get('scene'): 88 self.scene = self.user_params['scene'] 89 camera_id_combo = self.parse_hidden_camera_id() 90 self.camera_id = camera_id_combo[0] 91 if len(camera_id_combo) == 2: 92 self.hidden_physical_id = camera_id_combo[1] 93 else: 94 self.hidden_physical_id = None 95 96 num_devices = len(devices) 97 if num_devices == 2: # scenes [0,1,2,3,4,5,6] 98 try: 99 self.tablet = devices[1] 100 self.tablet_screen_brightness = self.user_params['brightness'] 101 except KeyError: 102 logging.debug('Not all tablet arguments set.') 103 else: # sensor_fusion or manual run 104 try: 105 self.fps = int(self.user_params['fps']) 106 img_size = self.user_params['img_size'].split(',') 107 self.img_w = int(img_size[0]) 108 self.img_h = int(img_size[1]) 109 self.test_length = float(self.user_params['test_length']) 110 self.rotator_cntl = self.user_params['rotator_cntl'] 111 self.rotator_ch = str(self.user_params['rotator_ch']) 112 except KeyError: 113 self.tablet = None 114 logging.debug('Not all arguments set. Manual run.') 115 116 self._setup_devices(num_devices) 117 118 def _setup_devices(self, num): 119 """Sets up each device in parallel if more than one device.""" 120 if num not in VALID_NUM_DEVICES: 121 raise AssertionError( 122 f'Incorrect number of devices! Must be in {str(VALID_NUM_DEVICES)}') 123 if num == 1: 124 self.setup_dut(self.dut) 125 else: 126 logic = lambda d: self.setup_dut(d) if d else self.setup_tablet() 127 utils.concurrent_exec( 128 logic, [(self.dut,), (None,)], 129 max_workers=2, 130 raise_on_exception=True) 131 132 def setup_dut(self, device): 133 self.dut.adb.shell( 134 'am start -n com.android.cts.verifier/.CtsVerifierActivity') 135 # Wait for the app screen to appear. 136 time.sleep(WAIT_TIME_SEC) 137 138 def setup_tablet(self): 139 # KEYCODE_POWER to reset dimmer timer. KEYCODE_WAKEUP no effect if ON. 140 self.tablet.adb.shell(['input', 'keyevent', 'KEYCODE_POWER']) 141 time.sleep(TABLET_CMD_DELAY_SEC) 142 self.tablet.adb.shell(['input', 'keyevent', 'KEYCODE_WAKEUP']) 143 time.sleep(TABLET_CMD_DELAY_SEC) 144 # Dismiss keyguard 145 self.tablet.adb.shell(['wm', 'dismiss-keyguard']) 146 time.sleep(TABLET_CMD_DELAY_SEC) 147 # Turn off the adaptive brightness on tablet. 148 self.tablet.adb.shell( 149 ['settings', 'put', 'system', 'screen_brightness_mode', 150 ADAPTIVE_BRIGHTNESS_OFF]) 151 # Set the screen brightness 152 self.tablet.adb.shell( 153 ['settings', 'put', 'system', 'screen_brightness', 154 str(self.tablet_screen_brightness)]) 155 logging.debug('Tablet brightness set to: %s', 156 format(self.tablet_screen_brightness)) 157 self.tablet.adb.shell('settings put system screen_off_timeout {}'.format( 158 TABLET_DIMMER_TIMEOUT_MS)) 159 self.set_tablet_landscape_orientation() 160 self.tablet.adb.shell('am force-stop com.google.android.apps.docs') 161 self.tablet.adb.shell('am force-stop com.google.android.apps.photos') 162 self.tablet.adb.shell('am force-stop com.android.gallery3d') 163 164 def set_tablet_landscape_orientation(self): 165 """Sets the screen orientation to landscape. 166 """ 167 # Get the landscape orientation value. 168 # This value is different for Pixel C/Huawei/Samsung tablets. 169 output = self.tablet.adb.shell('dumpsys window | grep mLandscapeRotation') 170 logging.debug('dumpsys window output: %s', output.decode('utf-8').strip()) 171 output_list = str(output.decode('utf-8')).strip().split(' ') 172 for val in output_list: 173 if 'LandscapeRotation' in val: 174 landscape_val = str(val.split('=')[-1]) 175 # For some tablets the values are in constant forms such as ROTATION_90 176 if 'ROTATION_90' in landscape_val: 177 landscape_val = '1' 178 logging.debug('Changing the orientation to landscape mode.') 179 self.tablet.adb.shell(['settings', 'put', 'system', 'user_rotation', 180 landscape_val]) 181 break 182 logging.debug('Reported tablet orientation is: %d', 183 int(self.tablet.adb.shell('settings get system user_rotation'))) 184 185 def parse_hidden_camera_id(self): 186 """Parse the string of camera ID into an array. 187 188 Returns: 189 Array with camera id and hidden_physical camera id. 190 """ 191 camera_id_combo = self.camera.split(its_session_utils.SUB_CAMERA_SEPARATOR) 192 return camera_id_combo 193 194 def determine_not_yet_mandated_tests(self, device_id, scene): 195 """Determine not_yet_mandated tests from NOT_YET_MANDATED list & phone info. 196 197 Args: 198 device_id: string of device id number. 199 scene: scene to which tests belong to. 200 201 Returns: 202 dict of not yet mandated tests 203 """ 204 # Initialize not_yet_mandated. 205 not_yet_mandated = {} 206 not_yet_mandated[scene] = [] 207 208 # Determine first API level for device. 209 first_api_level = its_session_utils.get_first_api_level(device_id) 210 211 # Determine which test are not yet mandated for first api level. 212 tests = NOT_YET_MANDATED[scene] 213 for [test, first_api_level_mandated] in tests: 214 logging.debug('First API level %s MANDATED: %d', 215 test, first_api_level_mandated) 216 if first_api_level < first_api_level_mandated: 217 not_yet_mandated[scene].append(test) 218 return not_yet_mandated 219 220 def on_pass(self, record): 221 logging.debug('%s on PASS.', record.test_name) 222 223 def on_fail(self, record): 224 logging.debug('%s on FAIL.', record.test_name) 225 if self.user_params.get('scene'): 226 not_yet_mandated_tests = self.determine_not_yet_mandated_tests( 227 self.dut.serial, self.scene) 228 if self.current_test_info.name in not_yet_mandated_tests[self.scene]: 229 logging.debug('%s is not yet mandated.', self.current_test_info.name) 230 asserts.fail('Not yet mandated test', extras='Not yet mandated test') 231 232 233