android-emulator-webrtc 1.0.17 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +93 -204
  2. package/dist/components/emulator/emulator.d.ts +64 -0
  3. package/dist/components/emulator/emulator.js +161 -173
  4. package/dist/components/emulator/net/emulator_status.d.ts +45 -0
  5. package/dist/components/emulator/net/emulator_status.js +35 -42
  6. package/dist/components/emulator/net/logcat.js +37 -54
  7. package/dist/components/emulator/net/logger.d.ts +7 -0
  8. package/dist/components/emulator/net/logger.js +20 -0
  9. package/dist/components/emulator/net/ws_jsep_protocol_driver.d.ts +213 -0
  10. package/dist/components/emulator/net/ws_jsep_protocol_driver.js +640 -0
  11. package/dist/components/emulator/views/event_handler.d.ts +37 -0
  12. package/dist/components/emulator/views/event_handler.js +274 -260
  13. package/dist/components/emulator/views/webrtc_view.d.ts +27 -0
  14. package/dist/components/emulator/views/webrtc_view.js +42 -25
  15. package/dist/index.d.ts +8 -0
  16. package/dist/index.js +0 -7
  17. package/dist/proto/emulator_controller_pb.d.ts +1 -0
  18. package/dist/proto/emulator_controller_pb.js +146 -287
  19. package/dist/src/components/emulator/emulator.d.ts +64 -0
  20. package/dist/src/components/emulator/net/emulator_status.d.ts +45 -0
  21. package/dist/src/components/emulator/net/logger.d.ts +7 -0
  22. package/dist/src/components/emulator/net/ws_jsep_protocol_driver.d.ts +213 -0
  23. package/dist/src/components/emulator/views/event_handler.d.ts +37 -0
  24. package/dist/src/components/emulator/views/webrtc_view.d.ts +27 -0
  25. package/dist/src/index.d.ts +8 -0
  26. package/dist/src/proto/emulator_controller_pb.d.ts +1 -0
  27. package/package.json +17 -18
  28. package/proto/emulator_controller.proto +746 -181
  29. package/.vscode/launch.json +0 -21
  30. package/.vscode/settings.json +0 -3
  31. package/CONTRIBUTING.md +0 -28
  32. package/Makefile +0 -123
  33. package/android-emulator-webrtc.code-workspace +0 -7
  34. package/api_descriptor.pb +0 -0
  35. package/babel.config.js +0 -16
  36. package/cloudbuild.yaml +0 -41
  37. package/cloudbuilders/.gcloudignore +0 -1
  38. package/cloudbuilders/Dockerfile +0 -20
  39. package/cloudbuilders/README.md +0 -29
  40. package/cloudbuilders/cloudbuild.yaml +0 -19
  41. package/dist/components/emulator/net/jsep_protocol_driver.js +0 -365
  42. package/dist/components/emulator/views/resizing_component.js +0 -86
  43. package/dist/components/emulator/views/simple_png_view.js +0 -111
  44. package/dist/proto/emulator_controller_grpc_web_pb.js +0 -1601
  45. package/dist/proto/emulator_web_client.js +0 -176
  46. package/dist/proto/rtc_service_grpc_web_pb.js +0 -231
  47. package/dist/proto/rtc_service_pb.js +0 -338
  48. package/emulator/index.js +0 -1
  49. package/eslint_prefix.py +0 -37
  50. package/gen_md_doc.js +0 -40
  51. package/npmrc.enc +0 -0
  52. package/proto/rtc_service.proto +0 -117
  53. package/protoc-plugin/Makefile +0 -31
  54. package/protoc-plugin/grpc_generator.cc +0 -1755
  55. package/src/components/emulator/emulator.js +0 -217
  56. package/src/components/emulator/net/emulator_status.js +0 -94
  57. package/src/components/emulator/net/jsep_protocol_driver.js +0 -364
  58. package/src/components/emulator/net/logcat.js +0 -155
  59. package/src/components/emulator/views/event_handler.js +0 -268
  60. package/src/components/emulator/views/resizing_component.js +0 -65
  61. package/src/components/emulator/views/simple_png_view.js +0 -106
  62. package/src/components/emulator/views/webrtc_view.js +0 -146
  63. package/src/index.js +0 -20
  64. package/src/proto/emulator_web_client.js +0 -140
  65. package/test/cloudbuild.yaml +0 -41
  66. package/test/emulator.test.js +0 -125
  67. package/test/event_handler.test.js +0 -91
  68. package/test/fake_events.js +0 -50
  69. package/test/jsep_protocol_driver.test.js +0 -228
  70. package/test/resizing_component.test.js +0 -37
  71. package/test/simple_png_view.test.js +0 -145
  72. package/test/touch_event_handler.test.js +0 -118
@@ -1,155 +0,0 @@
1
- /*
2
- * Copyright 2019 The Android Open Source Project
3
- *
4
- * Licensed under the Apache License, Version 2.0 (the "License")
5
- * you may not use this file except in compliance with the License.
6
- * You may obtain a copy of the License at
7
- *
8
- * http://www.apache.org/licenses/LICENSE-2.0
9
- *
10
- * Unless required by applicable law or agreed to in writing, software
11
- * distributed under the License is distributed on an "AS IS" BASIS,
12
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- * See the License for the specific language governing permissions and
14
- * limitations under the License.
15
- */
16
- import { EventEmitter } from "events";
17
- import "../../../proto/emulator_controller_pb";
18
- import { EmulatorControllerService } from "../../../proto/emulator_web_client";
19
-
20
- /**
21
- * Observe the logcat stream from the emulator.
22
- *
23
- * Streaming is done by either polling the emulator endpoint or making a streaming call.
24
- *
25
- * It will send out the following events:
26
- *
27
- * - `start` whenever the start method was called.
28
- * - `data` whenever new data became available.
29
- * - `end` whenever the stream is finished, either because it was stopped, or due to an error.
30
- */
31
- class Logcat {
32
- /**
33
- * Creates a logcat stream.
34
- *
35
- * The authentication service should implement the following methods:
36
- * - `authHeader()` which must return a set of headers that should be send along with a request.
37
- * - `unauthorized()` a function that gets called when a 401 was received.
38
- *
39
- * @constructor
40
- * @param {object} uriOrEmulator
41
- * @param {object} auth
42
- */
43
- constructor(uriOrEmulator, auth) {
44
- if (uriOrEmulator instanceof EmulatorControllerService) {
45
- this.emulator = uriOrEmulator;
46
- } else {
47
- this.emulator = new EmulatorControllerService(uriOrEmulator, auth);
48
- }
49
- this.offset = 0;
50
- this.lastline = "";
51
- this.stream = null;
52
- this.events = new EventEmitter();
53
- this.refreshRate = 1000;
54
- this.timerID = null;
55
- }
56
-
57
- /**
58
- * Register a listener.
59
- *
60
- * @param {string} name Name of the event.
61
- * @param {Callback} fn Function to notify on the given event.
62
- * @memberof Logcat
63
- */
64
- on = (name, fn) => {
65
- this.events.on(name, fn);
66
- };
67
-
68
- /**
69
- * Removes a listener.
70
- *
71
- * @param {string} name Name of the event.
72
- * @param {Callback} fn Function to notify on the given event.
73
- * @memberof Logcat
74
- */
75
- off = (name, fn) => {
76
- this.events.off(name, fn);
77
- };
78
-
79
- /**
80
- * Cancel the currently active logcat stream.
81
- *
82
- * @memberof Logcat
83
- */
84
- stop = () => {
85
- if (this.stream) {
86
- this.stream.cancel();
87
- }
88
- if (this.timerID) {
89
- clearInterval(this.timerID);
90
- this.timerID = null;
91
- }
92
- this.events.emit("end");
93
- };
94
-
95
- pollStream = () => {
96
- const self = this;
97
- /* eslint-disable */
98
- const request = new proto.android.emulation.control.LogMessage();
99
- request.setStart(this.offset);
100
- this.emulator.getLogcat(request, {}, (err, response) => {
101
- if (err) {
102
- this.stop();
103
- }
104
- if (response) {
105
- const nextOffset = response.getNext();
106
- if (nextOffset > self.offset) {
107
- self.offset = response.getNext();
108
- self.events.emit("data", response.getContents());
109
- }
110
- }
111
- });
112
- };
113
-
114
- // Uses streaming, this really locks up the ui, so best not to use for now.
115
- stream = () => {
116
- const self = this;
117
- /* eslint-disable */
118
- const request = new proto.android.emulation.control.LogMessage();
119
- request.setStart(this.offset);
120
- this.stream = this.emulator.streamLogcat(request);
121
- this.stream.on("data", (response) => {
122
- self.offset = response.getNext();
123
- const contents = response.getContents();
124
- self.events.emit("data", contents);
125
- });
126
- this.stream.on("error", (error) => {
127
- if ((error.code = 1)) {
128
- // Ignore we got cancelled.
129
- }
130
- });
131
- };
132
-
133
- /**
134
- * Requests the logcat stream, invoking the callback when a log line arrives.
135
- *
136
- * *Note:* Streaming can cause serious UI delays, so best not to use it.
137
- *
138
- * @param {Callback} fnNotify when a new log line arrives.
139
- * @param {number} refreshRate polling interval, or 0 if you wish to use streaming.
140
- * @memberof Logcat
141
- */
142
- start = (fnNotify, refreshRate = 1000) => {
143
- if (fnNotify) this.on("data", fnNotify);
144
-
145
- this.refreshRate = refreshRate;
146
- if (this.refreshRate > 0) {
147
- this.timerID = setInterval(() => this.pollStream(), this.refreshRate);
148
- } else {
149
- this.stream();
150
- }
151
- this.events.emit("start");
152
- };
153
- }
154
-
155
- export default Logcat;
@@ -1,268 +0,0 @@
1
- /*
2
- * Copyright 2019 The Android Open Source Project
3
- *
4
- * Licensed under the Apache License, Version 2.0 (the "License");
5
- * you may not use this file except in compliance with the License.
6
- * You may obtain a copy of the License at
7
- *
8
- * http://www.apache.org/licenses/LICENSE-2.0
9
- *
10
- * Unless required by applicable law or agreed to in writing, software
11
- * distributed under the License is distributed on an "AS IS" BASIS,
12
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- * See the License for the specific language governing permissions and
14
- * limitations under the License.
15
- */
16
- import PropTypes from "prop-types";
17
- import React from "react";
18
- import * as Proto from "../../../proto/emulator_controller_pb";
19
- import EmulatorStatus from "../net/emulator_status";
20
-
21
- /**
22
- * A handler that extends a view to send key/mouse events to the emulator.
23
- * It wraps the inner component in a div, and will use the jsep handler
24
- * to send key/mouse/touch events over the proper channel.
25
- *
26
- * It will translate the mouse events based upon the returned display size of
27
- * the emulator.
28
- *
29
- * You usually want to wrap a EmulatorRtcview, or EmulatorPngView in it.
30
- */
31
- export default function withMouseKeyHandler(WrappedComponent) {
32
- return class extends React.Component {
33
- constructor(props) {
34
- super(props);
35
- this.state = {
36
- deviceHeight: 1920,
37
- deviceWidth: 1080,
38
- mouse: {
39
- xp: 0,
40
- yp: 0,
41
- mouseDown: false, // Current state of mouse
42
- // Current button pressed.
43
- // In proto, 0 is "no button", 1 is left, and 2 is right.
44
- mouseButton: 0,
45
- },
46
- };
47
- this.handler = React.createRef();
48
- const { emulator } = this.props;
49
- this.status = new EmulatorStatus(emulator);
50
- }
51
-
52
- static propTypes = {
53
- /** The emulator object */
54
- emulator: PropTypes.object.isRequired,
55
- /** Jsep protocol driver, used to send mouse & touch events. */
56
- jsep: PropTypes.object.isRequired,
57
- };
58
-
59
- componentDidMount() {
60
- this.getScreenSize();
61
- }
62
-
63
- getScreenSize() {
64
- this.status.updateStatus((state) => {
65
- this.setState({
66
- deviceWidth: parseInt(state.hardwareConfig["hw.lcd.width"]) || 1080,
67
- deviceHeight: parseInt(state.hardwareConfig["hw.lcd.height"]) || 1920,
68
- });
69
- });
70
- }
71
-
72
- onContextMenu = (e) => {
73
- e.preventDefault();
74
- };
75
-
76
- scaleCoordinates = (xp, yp) => {
77
- // It is totally possible that we send clicks that are offscreen..
78
- const { deviceWidth, deviceHeight } = this.state;
79
- const { clientHeight, clientWidth } = this.handler.current;
80
- const scaleX = deviceWidth / clientWidth;
81
- const scaleY = deviceHeight / clientHeight;
82
- const x = Math.round(xp * scaleX);
83
- const y = Math.round(yp * scaleY);
84
-
85
- if (isNaN(x) || isNaN(y)) {
86
- console.log("Ignoring: x: " + x + ", y:" + y);
87
- return { x: -1, y: -1 };
88
- }
89
- return { x: x, y: y, scaleX: scaleX, scaleY: scaleY };
90
- };
91
-
92
- setMouseCoordinates = () => {
93
- // Forward the request to the jsep engine.
94
- const { mouseDown, mouseButton, xp, yp } = this.state.mouse;
95
- var request = new Proto.MouseEvent();
96
- const { x, y } = this.scaleCoordinates(xp, yp);
97
- request.setX(x);
98
- request.setY(y);
99
- request.setButtons(mouseDown ? mouseButton : 0);
100
- const { jsep } = this.props;
101
- jsep.send("mouse", request);
102
- };
103
-
104
- handleKey = (eventType) => {
105
- return (e) => {
106
- // Disable jumping to next control when pressing the space bar.
107
- if (e.keyCode === 32) {
108
- e.preventDefault();
109
- }
110
- var request = new Proto.KeyboardEvent();
111
- request.setEventtype(
112
- eventType === "KEYDOWN"
113
- ? Proto.KeyboardEvent.KeyEventType.KEYDOWN
114
- : eventType === "KEYUP"
115
- ? Proto.KeyboardEvent.KeyEventType.KEYUP
116
- : Proto.KeyboardEvent.KeyEventType.KEYPRESS
117
- );
118
- request.setKey(e.key);
119
- const { jsep } = this.props;
120
- jsep.send("keyboard", request);
121
- };
122
- };
123
-
124
- // Properly handle the mouse events.
125
- handleMouseDown = (e) => {
126
- const { offsetX, offsetY } = e.nativeEvent;
127
- this.setState(
128
- {
129
- mouse: {
130
- xp: offsetX,
131
- yp: offsetY,
132
- mouseDown: true,
133
- // In browser's MouseEvent.button property,
134
- // 0 stands for left button and 2 stands for right button.
135
- mouseButton: e.button === 0 ? 1 : e.button === 2 ? 2 : 0,
136
- },
137
- },
138
- this.setMouseCoordinates
139
- );
140
- };
141
-
142
- handleMouseUp = (e) => {
143
- const { offsetX, offsetY } = e.nativeEvent;
144
- this.setState(
145
- {
146
- mouse: { xp: offsetX, yp: offsetY, mouseDown: false, mouseButton: 0 },
147
- },
148
- this.setMouseCoordinates
149
- );
150
- };
151
-
152
- handleMouseMove = (e) => {
153
- // Let's not overload the endpoint with useless events.
154
- if (!this.state.mouse.mouseDown) return;
155
-
156
- const { offsetX, offsetY } = e.nativeEvent;
157
- var mouse = this.state.mouse;
158
- mouse.xp = offsetX;
159
- mouse.yp = offsetY;
160
- this.setState({ mouse: mouse }, this.setMouseCoordinates);
161
- };
162
-
163
- /**
164
- * Scales an axis to linux input codes that the emulator understands.
165
- *
166
- * @param {*} value The value to transform.
167
- * @param {*} minIn The minimum value, the lower bound of the value param.
168
- * @param {*} maxIn The maximum value, the upper bound of the value param.
169
- */
170
- scaleAxis = (value, minIn, maxIn) => {
171
- const minOut = 0x0; // EV_ABS_MIN
172
- const maxOut = 0x7fff; // EV_ABS_MAX
173
- const rangeOut = maxOut - minOut;
174
- const rangeIn = maxIn - minIn;
175
- if (rangeIn < 1) {
176
- return minOut + rangeOut / 2;
177
- }
178
- return (((value - minIn) * rangeOut) / rangeIn + minOut) | 0;
179
- };
180
-
181
- setTouchCoordinates = (type, touches, minForce, maxForce) => {
182
- // We need to calculate the offset of the touch events.
183
- const rect = this.handler.current.getBoundingClientRect();
184
- const scaleCoordinates = this.scaleCoordinates;
185
- const touchesToSend = Object.keys(touches).map((index) => {
186
- const touch = touches[index];
187
- const { clientX, clientY, identifier, force, radiusX, radiusY } = touch;
188
- const offsetX = clientX - rect.left;
189
- const offsetY = clientY - rect.top;
190
- const { x, y, scaleX, scaleY } = scaleCoordinates(offsetX, offsetY);
191
- const scaledRadiusX = 2 * radiusX * scaleX;
192
- const scaledRadiusY = 2 * radiusY * scaleY;
193
-
194
- const protoTouch = new Proto.Touch();
195
- protoTouch.setX(x | 0);
196
- protoTouch.setY(y | 0);
197
- protoTouch.setIdentifier(identifier);
198
-
199
- // Normalize the force
200
- const MT_PRESSURE = this.scaleAxis(
201
- Math.max(minForce, Math.min(maxForce, force)),
202
- 0,
203
- 1
204
- );
205
- protoTouch.setPressure(MT_PRESSURE);
206
- protoTouch.setTouchMajor(Math.max(scaledRadiusX, scaledRadiusY) | 0);
207
- protoTouch.setTouchMinor(Math.min(scaledRadiusX, scaledRadiusY) | 0);
208
-
209
- return protoTouch;
210
- });
211
-
212
- // Make the grpc call.
213
- const requestTouchEvent = new Proto.TouchEvent();
214
- requestTouchEvent.setTouchesList(touchesToSend);
215
- const { jsep } = this.props;
216
- jsep.send("touch", requestTouchEvent);
217
- };
218
-
219
- handleTouch = (minForce, maxForce) => {
220
- return (e) => {
221
- // Make sure they are not processed as mouse events later on.
222
- // See https://developer.mozilla.org/en-US/docs/Web/API/Touch_events
223
- if (e.cancelable) {
224
- e.preventDefault();
225
- }
226
- // Some browsers do net have a force sensor, so we have to "fake" values
227
- // for start/move/end events.
228
- this.setTouchCoordinates(
229
- e.nativeEvent.type,
230
- e.nativeEvent.changedTouches,
231
- minForce,
232
- maxForce
233
- );
234
- };
235
- };
236
-
237
- render() {
238
- return (
239
- <div /* handle interaction */
240
- onTouchStart={this.handleTouch(0.01, 1.0)}
241
- onTouchMove={this.handleTouch(0.01, 1.0)}
242
- onTouchEnd={this.handleTouch(0.0, 0.0)}
243
- onTouchCancel={this.handleTouch(0.0, 0.0)}
244
- onMouseDown={this.handleMouseDown}
245
- onMouseMove={this.handleMouseMove}
246
- onMouseUp={this.handleMouseUp}
247
- onMouseOut={this.handleMouseUp}
248
- onKeyDown={this.handleKey("KEYDOWN")}
249
- onKeyUp={this.handleKey("KEYUP")}
250
- onDragStart={this.preventDragHandler}
251
- tabIndex="0"
252
- ref={this.handler}
253
- style={{
254
- pointerEvents: "all",
255
- outline: "none",
256
- margin: "0",
257
- padding: "0",
258
- border: "0",
259
- display: "inline-block",
260
- width: "100%",
261
- }}
262
- >
263
- <WrappedComponent {...this.props} />
264
- </div>
265
- );
266
- }
267
- };
268
- }
@@ -1,65 +0,0 @@
1
- /**
2
- * @jest-environment jsdom
3
- */
4
- /*
5
- * Copyright 2023 The Android Open Source Project
6
- *
7
- * Licensed under the Apache License, Version 2.0 (the "License")
8
- * you may not use this file except in compliance with the License.
9
- * You may obtain a copy of the License at
10
- *
11
- * http://www.apache.org/licenses/LICENSE-2.0
12
- *
13
- * Unless required by applicable law or agreed to in writing, software
14
- * distributed under the License is distributed on an "AS IS" BASIS,
15
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
- * See the License for the specific language governing permissions and
17
- * limitations under the License.
18
- */
19
- import PropTypes from "prop-types";
20
- import React from "react";
21
- import useResizeObserver from "@react-hook/resize-observer";
22
-
23
- function useSize(target, onResize) {
24
- const [size, setSize] = React.useState();
25
-
26
- React.useLayoutEffect(() => {
27
- if (target) {
28
- const newSize = target.getBoundingClientRect();
29
- console.log(`Resizing to ${JSON.stringify(newSize)}`)
30
- setSize(newSize);
31
- if (onResize) {
32
- onResize(newSize);
33
- }
34
- }
35
- }, [target]);
36
-
37
- // Where the magic happens
38
- useResizeObserver(target, (entry) => {
39
- setSize(entry.contentRect);
40
- if (onResize) {
41
- console.log(`Resizing to ${JSON.stringify(entry.contentRect)}`)
42
- onResize(entry.contentRect);
43
- }
44
- });
45
- return size;
46
- }
47
-
48
- function ResizingComponent({ children, onResize, "data-testid": dataTestId, }) {
49
- // const ref = useRef();
50
- const [target, setTarget] = React.useState();
51
- const size = useSize(target, onResize);
52
-
53
- return (
54
- <div style={{ width: "100%", height: "100%" }} ref={setTarget} data-testid={dataTestId}>
55
- <div style={{ width: size?.width, height: size?.height }}>{children}</div>
56
- </div>
57
- );
58
- }
59
-
60
- ResizingComponent.propTypes = {
61
- onResize: PropTypes.func,
62
- "data-testid": PropTypes.string,
63
- };
64
-
65
- export default ResizingComponent;
@@ -1,106 +0,0 @@
1
- import PropTypes from "prop-types";
2
- import React, { useState, useEffect, useRef } from "react";
3
- import * as Proto from "../../../proto/emulator_controller_pb";
4
-
5
- const EmulatorPngView = ({
6
- emulator,
7
- onStateChange,
8
- poll,
9
- width,
10
- height,
11
- "data-testid": dataTestId,
12
- }) => {
13
- const [png, setPng] = useState("");
14
- const [connect, setConnect] = useState("connecting");
15
- var screenShot = null;
16
-
17
- useEffect(() => {
18
- startStream();
19
- return () => {
20
- setConnect("disconnected");
21
- if (screenShot) {
22
- screenShot.cancel();
23
- }
24
- };
25
- }, [width, height]);
26
-
27
- useEffect(() => {
28
- console.log("Png state changed to: " + connect);
29
- if (onStateChange) {
30
- onStateChange(connect);
31
- }
32
- }, [connect]);
33
-
34
- const startStream = () => {
35
- setConnect("connecting");
36
- const request = new Proto.ImageFormat();
37
- if (!isNaN(width)) {
38
- request.setWidth(Math.floor(width));
39
- }
40
- if (!isNaN(height)) {
41
- request.setWidth(Math.floor(height));
42
- }
43
-
44
- if (poll && connect !== "disconnected") {
45
- emulator.getScreenshot(request, {}, (err, response) => {
46
- setConnect("connected");
47
- setPng("data:image/jpeg;base64," + response.getImage_asB64());
48
- startStream();
49
- });
50
- } else {
51
- var receivedImage = false;
52
- screenShot = emulator.streamScreenshot(request);
53
- screenShot.on("data", (response) => {
54
- receivedImage = true;
55
- setConnect("connected");
56
- setPng("data:image/jpeg;base64," + response.getImage_asB64());
57
- });
58
- screenShot.on("error", (e) => {
59
- console.warn("Screenshot stream broken", e);
60
- if (receivedImage) {
61
- setConnect("connecting");
62
- startStream();
63
- } else {
64
- setConnect("disconnected");
65
- }
66
- });
67
- }
68
- };
69
-
70
- const preventDragHandler = (e) => {
71
- e.preventDefault();
72
- };
73
-
74
-
75
- return (
76
- <div
77
- width={width}
78
- style={{
79
- display: "block",
80
- position: "relative",
81
- height: "100%",
82
- objectFit: "contain",
83
- objectPosition: "center",
84
- }}
85
- onDragStart={preventDragHandler}
86
- >
87
- <img
88
- src={png}
89
- width="100%"
90
- draggable="false"
91
- style={{ pointerEvents: "none" }}
92
- />
93
- </div>
94
- );
95
- };
96
-
97
- EmulatorPngView.propTypes = {
98
- emulator: PropTypes.object,
99
- onStateChange: PropTypes.func,
100
- poll: PropTypes.bool,
101
- width: PropTypes.number,
102
- height: PropTypes.number,
103
- "data-testid": PropTypes.string,
104
- };
105
-
106
- export default EmulatorPngView;