Home | History | Annotate | Download | only in input_playback
      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 
      8 from autotest_lib.client.common_lib import error
      9 from autotest_lib.client.cros.graphics import graphics_utils
     10 from autotest_lib.client.cros.input_playback import input_playback
     11 
     12 _CLICK_EVENTS = '/tmp/click_events'
     13 _CLICK_TEMPLATE = 'click_events.template'
     14 _PREFIX_RESOLUTION = 'RESOLUTION'
     15 _PREFIX_POSITION = 'POSITION'
     16 _STYLUS_DEVICE = 'stylus'
     17 _STYLUS_PROPERTY = '/tmp/stylus.prop'
     18 _STYLUS_TEMPLATE = 'stylus.prop.template'
     19 
     20 
     21 class Stylus(object):
     22     """An emulated stylus device used for UI automation."""
     23 
     24     def __init__(self):
     25         """Prepare an emulated stylus device based on the internal display."""
     26         self.dirname = os.path.dirname(__file__)
     27         width, height = graphics_utils.get_internal_resolution()
     28         logging.info('internal display W = %d H = %d ', width, height)
     29         # Skip the test if there is no internal display
     30         if width == -1:
     31             raise error.TestNAError('No internal display')
     32 
     33         # Enlarge resolution of the emulated stylus.
     34         self.width = width * 10
     35         self.height = height * 10
     36         stylus_template = os.path.join(self.dirname, _STYLUS_TEMPLATE)
     37         self.replace_with_prefix(stylus_template, _STYLUS_PROPERTY,
     38                                  _PREFIX_RESOLUTION, self.width, self.height)
     39         # Create an emulated stylus device.
     40         self.stylus = input_playback.InputPlayback()
     41         self.stylus.emulate(input_type=_STYLUS_DEVICE,
     42                             property_file=_STYLUS_PROPERTY)
     43         self.stylus.find_connected_inputs()
     44 
     45     def replace_with_prefix(self, in_file, out_file, prefix, x_value, y_value):
     46         """Substitute with the real positions and write to an output file.
     47 
     48         Replace the keywords in template file with the real values and save
     49         the results into a file.
     50 
     51         @param in_file: the template file containing keywords for substitution.
     52         @param out_file: the generated file after substitution.
     53         @param prefix: the prefix of the keywords for substituion.
     54         @param x_value: the target value of X.
     55         @param y_value: the target value of Y.
     56 
     57         """
     58         with open(in_file) as infile:
     59             content = infile.readlines()
     60 
     61         with open(out_file, 'w') as outfile:
     62             for line in content:
     63                 if line.find(prefix + '_X') > 0:
     64                     line = line.replace(prefix + '_X', str(x_value))
     65                     x_value += 1
     66                 else:
     67                     if line.find(prefix + '_Y') > 0:
     68                         line = line.replace(prefix + '_Y', str(y_value))
     69                         y_value += 1
     70                 outfile.write(line)
     71 
     72     def click(self, position_x, position_y):
     73         """Click the point(x,y) on the emulated stylus panel.
     74 
     75         @param position_x: the X position of the click point.
     76         @param position_y: the Y position of the click point.
     77 
     78         """
     79         click_template = os.path.join(self.dirname, _CLICK_TEMPLATE)
     80         self.replace_with_prefix(click_template,
     81                                  _CLICK_EVENTS,
     82                                  _PREFIX_POSITION,
     83                                  position_x * 10,
     84                                  position_y * 10)
     85         self.stylus.blocking_playback(_CLICK_EVENTS, input_type=_STYLUS_DEVICE)
     86 
     87     def click_with_percentage(self, percent_x, percent_y):
     88         """Click a point based on the percentage of the display.
     89 
     90         @param percent_x: the percentage of X position over display width.
     91         @param percent_y: the percentage of Y position over display height.
     92 
     93         """
     94         position_x = int(percent_x * self.width / 10)
     95         position_y = int(percent_y * self.height / 10)
     96         self.click(position_x, position_y)
     97 
     98     def close(self):
     99         """Clean up the files/handles created in the class."""
    100         if self.stylus:
    101             self.stylus.close()
    102         if os.path.exists(_STYLUS_PROPERTY):
    103             os.remove(_STYLUS_PROPERTY)
    104         if os.path.exists(_CLICK_EVENTS):
    105             os.remove(_CLICK_EVENTS)
    106