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.
- package/README.md +93 -204
- package/dist/components/emulator/emulator.d.ts +64 -0
- package/dist/components/emulator/emulator.js +161 -173
- package/dist/components/emulator/net/emulator_status.d.ts +45 -0
- package/dist/components/emulator/net/emulator_status.js +35 -42
- package/dist/components/emulator/net/logcat.js +37 -54
- package/dist/components/emulator/net/logger.d.ts +7 -0
- package/dist/components/emulator/net/logger.js +20 -0
- package/dist/components/emulator/net/ws_jsep_protocol_driver.d.ts +213 -0
- package/dist/components/emulator/net/ws_jsep_protocol_driver.js +640 -0
- package/dist/components/emulator/views/event_handler.d.ts +37 -0
- package/dist/components/emulator/views/event_handler.js +274 -260
- package/dist/components/emulator/views/webrtc_view.d.ts +27 -0
- package/dist/components/emulator/views/webrtc_view.js +42 -25
- package/dist/index.d.ts +8 -0
- package/dist/index.js +0 -7
- package/dist/proto/emulator_controller_pb.d.ts +1 -0
- package/dist/proto/emulator_controller_pb.js +146 -287
- package/dist/src/components/emulator/emulator.d.ts +64 -0
- package/dist/src/components/emulator/net/emulator_status.d.ts +45 -0
- package/dist/src/components/emulator/net/logger.d.ts +7 -0
- package/dist/src/components/emulator/net/ws_jsep_protocol_driver.d.ts +213 -0
- package/dist/src/components/emulator/views/event_handler.d.ts +37 -0
- package/dist/src/components/emulator/views/webrtc_view.d.ts +27 -0
- package/dist/src/index.d.ts +8 -0
- package/dist/src/proto/emulator_controller_pb.d.ts +1 -0
- package/package.json +17 -18
- package/proto/emulator_controller.proto +746 -181
- package/.vscode/launch.json +0 -21
- package/.vscode/settings.json +0 -3
- package/CONTRIBUTING.md +0 -28
- package/Makefile +0 -123
- package/android-emulator-webrtc.code-workspace +0 -7
- package/api_descriptor.pb +0 -0
- package/babel.config.js +0 -16
- package/cloudbuild.yaml +0 -41
- package/cloudbuilders/.gcloudignore +0 -1
- package/cloudbuilders/Dockerfile +0 -20
- package/cloudbuilders/README.md +0 -29
- package/cloudbuilders/cloudbuild.yaml +0 -19
- package/dist/components/emulator/net/jsep_protocol_driver.js +0 -365
- package/dist/components/emulator/views/resizing_component.js +0 -86
- package/dist/components/emulator/views/simple_png_view.js +0 -111
- package/dist/proto/emulator_controller_grpc_web_pb.js +0 -1601
- package/dist/proto/emulator_web_client.js +0 -176
- package/dist/proto/rtc_service_grpc_web_pb.js +0 -231
- package/dist/proto/rtc_service_pb.js +0 -338
- package/emulator/index.js +0 -1
- package/eslint_prefix.py +0 -37
- package/gen_md_doc.js +0 -40
- package/npmrc.enc +0 -0
- package/proto/rtc_service.proto +0 -117
- package/protoc-plugin/Makefile +0 -31
- package/protoc-plugin/grpc_generator.cc +0 -1755
- package/src/components/emulator/emulator.js +0 -217
- package/src/components/emulator/net/emulator_status.js +0 -94
- package/src/components/emulator/net/jsep_protocol_driver.js +0 -364
- package/src/components/emulator/net/logcat.js +0 -155
- package/src/components/emulator/views/event_handler.js +0 -268
- package/src/components/emulator/views/resizing_component.js +0 -65
- package/src/components/emulator/views/simple_png_view.js +0 -106
- package/src/components/emulator/views/webrtc_view.js +0 -146
- package/src/index.js +0 -20
- package/src/proto/emulator_web_client.js +0 -140
- package/test/cloudbuild.yaml +0 -41
- package/test/emulator.test.js +0 -125
- package/test/event_handler.test.js +0 -91
- package/test/fake_events.js +0 -50
- package/test/jsep_protocol_driver.test.js +0 -228
- package/test/resizing_component.test.js +0 -37
- package/test/simple_png_view.test.js +0 -145
- 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;
|