blob: 44ea06f4bbff10e4437aac1bb7704546cc17b66a [file] [log] [blame]
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +08001# Copyright (c) 2014 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
Tom Wai-Hong Tam4c8022f2014-07-17 09:12:08 +08005import Image
Tom Wai-Hong Tam0d836592014-04-23 11:27:40 +08006import httplib
7import logging
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +08008import os
Tom Wai-Hong Tam0d836592014-04-23 11:27:40 +08009import socket
Tom Wai-Hong Tam897fcf72014-04-25 14:02:54 +080010import tempfile
Tom Wai-Hong Tam0d836592014-04-23 11:27:40 +080011import xmlrpclib
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +080012
13from autotest_lib.client.bin import utils
Tom Wai-Hong Tam0d836592014-04-23 11:27:40 +080014from autotest_lib.client.common_lib.cros import retry
Wai-Hong Tam44cb5452014-03-18 16:14:24 -070015from autotest_lib.client.cros import constants
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +080016from autotest_lib.server import autotest
Tom Wai-Hong Tam897fcf72014-04-25 14:02:54 +080017from autotest_lib.server.cros.chameleon import image_generator
18
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +080019
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +080020class DisplayClient(object):
21 """DisplayClient is a layer to control display logic over a remote DUT.
22
23 The Autotest host object representing the remote DUT, passed to this
24 class on initialization, can be accessed from its _client property.
25
26 """
27
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +080028 X_ENV_VARIABLES = 'DISPLAY=:0.0 XAUTHORITY=/home/chronos/.Xauthority'
29 XMLRPC_CONNECT_TIMEOUT = 30
Tom Wai-Hong Tam0d836592014-04-23 11:27:40 +080030 XMLRPC_RETRY_TIMEOUT = 180
31 XMLRPC_RETRY_DELAY = 10
Tom Wai-Hong Tam23362632014-04-09 16:38:37 +080032 HTTP_PORT = 8000
Tom Wai-Hong Tam897fcf72014-04-25 14:02:54 +080033 DEST_TMP_DIR = '/tmp'
34 DEST_IMAGE_FILENAME = 'calibration.svg'
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +080035
36
37 def __init__(self, host):
38 """Construct a DisplayClient.
39
40 @param host: Host object representing a remote host.
41 """
42 self._client = host
43 self._display_xmlrpc_client = None
Tom Wai-Hong Tam897fcf72014-04-25 14:02:54 +080044 self._image_generator = image_generator.ImageGenerator()
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +080045
46
Wai-Hong Tam44cb5452014-03-18 16:14:24 -070047 def initialize(self):
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +080048 """Initializes some required servers, like HTTP daemon, RPC connection.
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +080049 """
50 # Make sure the client library is on the device so that the proxy code
51 # is there when we try to call it.
52 client_at = autotest.Autotest(self._client)
53 client_at.install()
Tom Wai-Hong Tamfe395092014-02-12 20:16:22 +080054 self.connect()
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +080055
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +080056
Tom Wai-Hong Tamfe395092014-02-12 20:16:22 +080057 def connect(self):
58 """Connects the XML-RPC proxy on the client."""
Tom Wai-Hong Tam0d836592014-04-23 11:27:40 +080059 @retry.retry((socket.error,
60 xmlrpclib.ProtocolError,
61 httplib.BadStatusLine),
62 timeout_min=self.XMLRPC_RETRY_TIMEOUT / 60.0,
63 delay_sec=self.XMLRPC_RETRY_DELAY)
64 def connect_with_retries():
65 """Connects the XML-RPC proxy with retries."""
66 self._display_xmlrpc_client = self._client.xmlrpc_connect(
67 constants.DISPLAY_TESTING_XMLRPC_SERVER_COMMAND,
68 constants.DISPLAY_TESTING_XMLRPC_SERVER_PORT,
69 command_name=(
70 constants.DISPLAY_TESTING_XMLRPC_SERVER_CLEANUP_PATTERN
71 ),
72 ready_test_name=(
73 constants.DISPLAY_TESTING_XMLRPC_SERVER_READY_METHOD),
74 timeout_seconds=self.XMLRPC_CONNECT_TIMEOUT)
75
76 logging.info('Setup the display_client RPC server, with retries...')
77 connect_with_retries()
Tom Wai-Hong Tamfe395092014-02-12 20:16:22 +080078
79
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +080080 def cleanup(self):
81 """Cleans up."""
Tom Wai-Hong Tam0d836592014-04-23 11:27:40 +080082 self._client.rpc_disconnect(
83 constants.DISPLAY_TESTING_XMLRPC_SERVER_PORT)
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +080084
85
86 def __del__(self):
87 """Destructor of DisplayClient."""
88 self.cleanup()
89
90
91 def get_connector_name(self):
92 """Gets the name of the external output connector.
93
94 @return The external output connector name as a string.
95 """
96 return self._display_xmlrpc_client.get_ext_connector_name()
97
98
99 def load_calibration_image(self, resolution):
100 """Load a full screen calibration image from the HTTP server.
101
102 @param resolution: A tuple (width, height) of resolution.
103 """
Tom Wai-Hong Tam897fcf72014-04-25 14:02:54 +0800104 with tempfile.NamedTemporaryFile() as f:
105 self._image_generator.generate_image(
106 resolution[0], resolution[1], f.name)
107 os.chmod(f.name, 0644)
108 self._client.send_file(
109 f.name,
110 os.path.join(self.DEST_TMP_DIR, self.DEST_IMAGE_FILENAME))
111
112 page_url = 'file://%s/%s' % (self.DEST_TMP_DIR,
113 self.DEST_IMAGE_FILENAME)
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +0800114 self._display_xmlrpc_client.load_url(page_url)
115
116
117 def close_tab(self, index=-1):
118 """Closes the tab of the given index.
119
120 @param index: The tab index to close. Defaults to the last tab.
121 """
122 return self._display_xmlrpc_client.close_tab(index)
123
124
125 def set_mirrored(self, is_mirrored):
126 """Sets mirrored mode.
127
128 @param is_mirrored: True or False to indicate mirrored state.
129 """
130 return self._display_xmlrpc_client.set_mirrored(is_mirrored)
131
132
Tom Wai-Hong Tam328dbeb2014-02-14 11:20:19 +0800133 def suspend_resume(self, suspend_time=10):
134 """Suspends the DUT for a given time in second.
135
136 @param suspend_time: Suspend time in second, default: 10s.
137 """
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +0800138 # TODO(waihong): Use other general API instead of this RPC.
Tom Wai-Hong Tam328dbeb2014-02-14 11:20:19 +0800139 return self._display_xmlrpc_client.suspend_resume(suspend_time)
140
141
142 def suspend_resume_bg(self, suspend_time=10):
143 """Suspends the DUT for a given time in second in the background.
144
145 @param suspend_time: Suspend time in second, default: 10s.
146 """
147 # TODO(waihong): Use other general API instead of this RPC.
148 return self._display_xmlrpc_client.suspend_resume_bg(suspend_time)
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +0800149
150
151 def reconnect_output_and_wait(self):
152 """Reconnects output and waits it available."""
153 output = self.get_connector_name()
154 self._display_xmlrpc_client.reconnect_output(output)
155 self._display_xmlrpc_client.wait_output_connected(output)
156 utils.wait_for_value(lambda: (
157 len(self._display_xmlrpc_client.get_display_info())),
158 expected_value=2)
159
160
Hung-ying Tyan67541652014-03-12 11:44:46 +0800161 def hide_cursor(self):
162 """Hides mouse cursor by sending a keystroke."""
Tom Wai-Hong Tambd22f8f2014-06-03 03:05:56 +0800163 self._display_xmlrpc_client.press_key('Up')
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +0800164
165
Tom Wai-Hong Tam4c8022f2014-07-17 09:12:08 +0800166 def capture_external_screen(self):
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +0800167 """Captures the external screen framebuffer.
168
Tom Wai-Hong Tam4c8022f2014-07-17 09:12:08 +0800169 @return: An Image object.
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +0800170 """
171 output = self.get_connector_name()
172 fb_w, fb_h, fb_x, fb_y = (
173 self._display_xmlrpc_client.get_resolution(output))
Tom Wai-Hong Tam4c8022f2014-07-17 09:12:08 +0800174 with tempfile.NamedTemporaryFile(suffix='.png') as f:
175 basename = os.path.basename(f.name)
176 remote_path = os.path.join('/tmp', basename)
177 command = ('%s import -window root -depth 8 -crop %dx%d+%d+%d %s' %
178 (self.X_ENV_VARIABLES, fb_w, fb_h, fb_x, fb_y,
179 remote_path))
180 self._client.run(command)
181 self._client.get_file(remote_path, f.name)
182 return Image.open(f.name)
Tom Wai-Hong Tamf6bb17f2014-04-24 13:36:49 +0800183
184
185 def get_resolution(self):
186 """Gets the external resolution on framebuffer.
187
188 @return The resolution tuple (width, height)
189 """
190 output = self.get_connector_name()
191 width, height, _, _ = self._display_xmlrpc_client.get_resolution(output)
192 return (width, height)