android-emulator-webrtc 1.0.13 → 1.0.16
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/Makefile +8 -13
- package/dist/components/emulator/emulator.js +7 -3
- package/dist/components/emulator/net/jsep_protocol_driver.js +1 -1
- package/dist/components/emulator/views/event_handler.js +7 -3
- package/dist/components/emulator/views/simple_png_view.js +32 -13
- package/dist/components/emulator/views/webrtc_view.js +7 -3
- package/dist/proto/emulator_web_client.js +2 -2
- package/package.json +1 -1
- package/src/components/emulator/net/jsep_protocol_driver.js +1 -1
- package/src/components/emulator/views/simple_png_view.js +28 -12
- package/test/event_handler.test.js +1 -29
- package/test/fake_events.js +50 -0
- package/test/jsep_protocol_driver.test.js +0 -1
- package/test/simple_png_view.test.js +133 -0
package/Makefile
CHANGED
|
@@ -43,12 +43,9 @@ endif
|
|
|
43
43
|
|
|
44
44
|
MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
|
|
45
45
|
CURRENT_DIR := $(abspath $(MAKEFILE_PATH)/..)
|
|
46
|
-
QEMU_ROOT := $(abspath $(AOSP)/external/qemu)
|
|
47
|
-
GRPC_ROOT := $(QEMU_ROOT)/objs/distribution/emulator/lib
|
|
48
|
-
|
|
49
46
|
# Protobuf settings. If you are running this in the AOSP tree you will want to run ninja install first.
|
|
50
47
|
PROTODIR := $(CURRENT_DIR)/src/proto/
|
|
51
|
-
PROTOSRCDIR := $(
|
|
48
|
+
PROTOSRCDIR := $(CURRENT_DIR)/proto
|
|
52
49
|
PROTO_SRC := $(wildcard $(PROTOSRCDIR)/*.proto)
|
|
53
50
|
PROTO_OBJS := $(addprefix $(PROTODIR)/, $(notdir $(PROTO_SRC:.proto=_pb.js)))
|
|
54
51
|
PROXY_OBJS := $(addprefix $(PROTODIR)/, $(notdir $(PROTO_SRC:.proto=_grpc_web_pb.js)))
|
|
@@ -61,12 +58,10 @@ LDFLAGS += -L$(PROTOLIB) -lprotoc -lprotobuf -lpthread -ldl
|
|
|
61
58
|
|
|
62
59
|
.PHONY: build-release run-release develop stop
|
|
63
60
|
|
|
64
|
-
all:
|
|
61
|
+
all: check
|
|
65
62
|
|
|
66
63
|
clean:
|
|
67
|
-
rm -rf $(PROTODIR)
|
|
68
|
-
rm -rf emulator
|
|
69
|
-
|
|
64
|
+
rm -rf $(PROTODIR)/*pb.js
|
|
70
65
|
|
|
71
66
|
$(PROTODIR):
|
|
72
67
|
@mkdir -p $(PROTODIR)
|
|
@@ -80,7 +75,7 @@ $(PROTODIR)/%_pb.js : $(PROTOSRCDIR)/%.proto $(PROTODIR) protoc-gen-grpc-web
|
|
|
80
75
|
$(PROTOC) \
|
|
81
76
|
-I/usr/local/include -I$(PROTODIR) -I$(PROTOSRCDIR) \
|
|
82
77
|
--plugin=protoc-gen-grpc-web=$(CURRENT_DIR)/protoc-gen-grpc-web \
|
|
83
|
-
--js_out=import_style=commonjs:$(PROTODIR) \
|
|
78
|
+
--js_out=import_style=commonjs,binary:$(PROTODIR) \
|
|
84
79
|
--grpc-web_out=import_style=commonjs,mode=grpcwebtext:$(PROTODIR) \
|
|
85
80
|
$<
|
|
86
81
|
$(PREFIX_ESLINT) $@
|
|
@@ -90,19 +85,19 @@ $(PROTODIR)/%_pb.js : $(PROTOSRCDIR)/%.proto $(PROTODIR) protoc-gen-grpc-web
|
|
|
90
85
|
$(PROTODIR)/%_grpc_web_pb.js : $(PROTODIR)/%_pb.js
|
|
91
86
|
@test -f $@ && $(PREFIX_ESLINT) $@ || true
|
|
92
87
|
|
|
93
|
-
|
|
94
|
-
protoc: $(PROTO_OBJS) $(PROXY_OBJS) $(PROTODIR)/emulator_web_client.js
|
|
88
|
+
protoc: $(PROTO_OBJS) $(PROXY_OBJS)
|
|
95
89
|
|
|
96
90
|
protoc-gen-grpc-web: protoc-plugin/grpc_generator.o
|
|
97
91
|
$(CXX) $^ $(LDFLAGS) -o $@
|
|
98
92
|
|
|
99
|
-
deps:
|
|
93
|
+
deps: system-check protoc
|
|
100
94
|
@npm install
|
|
101
95
|
|
|
102
|
-
|
|
103
96
|
build: deps
|
|
104
97
|
@npm run build
|
|
105
98
|
|
|
99
|
+
check: build
|
|
100
|
+
@npm run test
|
|
106
101
|
|
|
107
102
|
system-check:
|
|
108
103
|
ifneq ($(HAS_VALID_PROTOC),true)
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
|
|
4
|
-
|
|
5
3
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
6
4
|
|
|
5
|
+
var _typeof = require("@babel/runtime/helpers/typeof");
|
|
6
|
+
|
|
7
7
|
Object.defineProperty(exports, "__esModule", {
|
|
8
8
|
value: true
|
|
9
9
|
});
|
|
@@ -39,9 +39,13 @@ var Proto = _interopRequireWildcard(require("../../proto/emulator_controller_pb"
|
|
|
39
39
|
|
|
40
40
|
var _emulator_web_client = require("../../proto/emulator_web_client");
|
|
41
41
|
|
|
42
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
43
|
+
|
|
44
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
45
|
+
|
|
42
46
|
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2["default"])(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2["default"])(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2["default"])(this, result); }; }
|
|
43
47
|
|
|
44
|
-
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try {
|
|
48
|
+
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
|
|
45
49
|
|
|
46
50
|
var PngView = (0, _event_handler["default"])(_simple_png_view["default"]);
|
|
47
51
|
var RtcView = (0, _event_handler["default"])(_webrtc_view["default"]);
|
|
@@ -277,7 +277,7 @@ var JsepProtocol = /*#__PURE__*/function () {
|
|
|
277
277
|
_this._handleSDP(_this.old_emu_patch.sdp);
|
|
278
278
|
}
|
|
279
279
|
|
|
280
|
-
if (_this.haveOffer) {
|
|
280
|
+
if (_this.old_emu_patch.haveOffer) {
|
|
281
281
|
// We have a remote peer, add the candidates in.
|
|
282
282
|
while (_this.old_emu_patch.candidates.length > 0) {
|
|
283
283
|
_this._handleCandidate(_this.old_emu_patch.candidates.shift());
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
|
|
4
|
-
|
|
5
3
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
6
4
|
|
|
5
|
+
var _typeof = require("@babel/runtime/helpers/typeof");
|
|
6
|
+
|
|
7
7
|
Object.defineProperty(exports, "__esModule", {
|
|
8
8
|
value: true
|
|
9
9
|
});
|
|
@@ -31,9 +31,13 @@ var Proto = _interopRequireWildcard(require("../../../proto/emulator_controller_
|
|
|
31
31
|
|
|
32
32
|
var _emulator_status = _interopRequireDefault(require("../net/emulator_status"));
|
|
33
33
|
|
|
34
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
35
|
+
|
|
36
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
37
|
+
|
|
34
38
|
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2["default"])(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2["default"])(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2["default"])(this, result); }; }
|
|
35
39
|
|
|
36
|
-
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try {
|
|
40
|
+
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
|
|
37
41
|
|
|
38
42
|
/**
|
|
39
43
|
* A handler that extends a view to send key/mouse events to the emulator.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
|
|
4
|
-
|
|
5
3
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
6
4
|
|
|
5
|
+
var _typeof = require("@babel/runtime/helpers/typeof");
|
|
6
|
+
|
|
7
7
|
Object.defineProperty(exports, "__esModule", {
|
|
8
8
|
value: true
|
|
9
9
|
});
|
|
@@ -31,9 +31,13 @@ var Proto = _interopRequireWildcard(require("../../../proto/emulator_controller_
|
|
|
31
31
|
|
|
32
32
|
var _reactResizeObserver = _interopRequireDefault(require("react-resize-observer"));
|
|
33
33
|
|
|
34
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
35
|
+
|
|
36
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
37
|
+
|
|
34
38
|
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2["default"])(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2["default"])(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2["default"])(this, result); }; }
|
|
35
39
|
|
|
36
|
-
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try {
|
|
40
|
+
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
|
|
37
41
|
|
|
38
42
|
/**
|
|
39
43
|
* A view on the emulator that is generated by streaming a series of screenshots.
|
|
@@ -60,7 +64,7 @@ var EmulatorPngView = /*#__PURE__*/function (_Component) {
|
|
|
60
64
|
png: "",
|
|
61
65
|
width: null,
|
|
62
66
|
height: null,
|
|
63
|
-
connect: "
|
|
67
|
+
connect: "connecting"
|
|
64
68
|
});
|
|
65
69
|
(0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "preventDragHandler", function (e) {
|
|
66
70
|
e.preventDefault();
|
|
@@ -104,7 +108,7 @@ var EmulatorPngView = /*#__PURE__*/function (_Component) {
|
|
|
104
108
|
var _this$state = this.state,
|
|
105
109
|
width = _this$state.width,
|
|
106
110
|
height = _this$state.height,
|
|
107
|
-
|
|
111
|
+
connect = _this$state.connect;
|
|
108
112
|
|
|
109
113
|
if (this.screen) {
|
|
110
114
|
this.screen.cancel();
|
|
@@ -122,7 +126,7 @@ var EmulatorPngView = /*#__PURE__*/function (_Component) {
|
|
|
122
126
|
emulator = _this$props.emulator,
|
|
123
127
|
poll = _this$props.poll;
|
|
124
128
|
|
|
125
|
-
if (poll &&
|
|
129
|
+
if (poll && connect !== "disconnected") {
|
|
126
130
|
emulator.getScreenshot(request, {}, function (err, response) {
|
|
127
131
|
_this2.setState({
|
|
128
132
|
connect: "connected"
|
|
@@ -131,22 +135,34 @@ var EmulatorPngView = /*#__PURE__*/function (_Component) {
|
|
|
131
135
|
|
|
132
136
|
self.setState({
|
|
133
137
|
png: "data:image/jpeg;base64," + response.getImage_asB64()
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
_this2.startStream(width, height);
|
|
138
|
+
}, _this2.startStream);
|
|
137
139
|
});
|
|
138
140
|
} else {
|
|
139
141
|
this.screen = emulator.streamScreenshot(request);
|
|
140
142
|
this.screen.on("data", function (response) {
|
|
141
|
-
|
|
143
|
+
self.setState({
|
|
142
144
|
connect: "connected"
|
|
143
145
|
}, _this2.broadcastState); // Update the image with the one we just received.
|
|
144
146
|
|
|
145
|
-
|
|
146
147
|
self.setState({
|
|
147
148
|
png: "data:image/jpeg;base64," + response.getImage_asB64()
|
|
148
149
|
});
|
|
149
150
|
});
|
|
151
|
+
this.screen.on("error", function (e) {
|
|
152
|
+
console.warn("Screenshot stream broken", e);
|
|
153
|
+
var connect = _this2.state.connect;
|
|
154
|
+
|
|
155
|
+
if (connect === "connected") {
|
|
156
|
+
console.log("Reconnecting..");
|
|
157
|
+
self.setState({
|
|
158
|
+
connect: "connecting"
|
|
159
|
+
}, _this2.startStream);
|
|
160
|
+
} else {
|
|
161
|
+
self.setState({
|
|
162
|
+
connect: "disconnected"
|
|
163
|
+
}, _this2.broadcastState);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
150
166
|
}
|
|
151
167
|
}
|
|
152
168
|
}, {
|
|
@@ -165,7 +181,7 @@ var EmulatorPngView = /*#__PURE__*/function (_Component) {
|
|
|
165
181
|
},
|
|
166
182
|
onDragStart: this.preventDragHandler
|
|
167
183
|
}, /*#__PURE__*/_react["default"].createElement(_reactResizeObserver["default"], {
|
|
168
|
-
|
|
184
|
+
onReflow: function onReflow(rect) {
|
|
169
185
|
self.setState({
|
|
170
186
|
width: rect.width,
|
|
171
187
|
height: rect.height
|
|
@@ -174,7 +190,10 @@ var EmulatorPngView = /*#__PURE__*/function (_Component) {
|
|
|
174
190
|
}), /*#__PURE__*/_react["default"].createElement("img", {
|
|
175
191
|
src: this.state.png,
|
|
176
192
|
width: "100%",
|
|
177
|
-
draggable: "false"
|
|
193
|
+
draggable: "false",
|
|
194
|
+
style: {
|
|
195
|
+
pointerEvents: "none"
|
|
196
|
+
}
|
|
178
197
|
}));
|
|
179
198
|
}
|
|
180
199
|
}]);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
|
|
4
|
-
|
|
5
3
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
6
4
|
|
|
5
|
+
var _typeof = require("@babel/runtime/helpers/typeof");
|
|
6
|
+
|
|
7
7
|
Object.defineProperty(exports, "__esModule", {
|
|
8
8
|
value: true
|
|
9
9
|
});
|
|
@@ -27,9 +27,13 @@ var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
|
27
27
|
|
|
28
28
|
var _react = _interopRequireWildcard(require("react"));
|
|
29
29
|
|
|
30
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
31
|
+
|
|
32
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
33
|
+
|
|
30
34
|
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2["default"])(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2["default"])(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2["default"])(this, result); }; }
|
|
31
35
|
|
|
32
|
-
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try {
|
|
36
|
+
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
|
|
33
37
|
|
|
34
38
|
/**
|
|
35
39
|
* A view on the emulator that is using WebRTC. It will use the Jsep protocol over gRPC to
|
|
@@ -29,13 +29,13 @@ var _grpcWeb = require("grpc-web");
|
|
|
29
29
|
|
|
30
30
|
var _events = require("events");
|
|
31
31
|
|
|
32
|
-
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
|
|
32
|
+
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
|
|
33
33
|
|
|
34
34
|
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
|
|
35
35
|
|
|
36
36
|
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2["default"])(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2["default"])(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2["default"])(this, result); }; }
|
|
37
37
|
|
|
38
|
-
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try {
|
|
38
|
+
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
|
|
39
39
|
|
|
40
40
|
var NopAuthenticator = function NopAuthenticator() {
|
|
41
41
|
(0, _classCallCheck2["default"])(this, NopAuthenticator);
|
package/package.json
CHANGED
|
@@ -271,7 +271,7 @@ export default class JsepProtocol {
|
|
|
271
271
|
this._handleSDP(this.old_emu_patch.sdp);
|
|
272
272
|
}
|
|
273
273
|
|
|
274
|
-
if (this.haveOffer) {
|
|
274
|
+
if (this.old_emu_patch.haveOffer) {
|
|
275
275
|
// We have a remote peer, add the candidates in.
|
|
276
276
|
while (this.old_emu_patch.candidates.length > 0) {
|
|
277
277
|
this._handleCandidate(this.old_emu_patch.candidates.shift());
|
|
@@ -51,7 +51,7 @@ export default class EmulatorPngView extends Component {
|
|
|
51
51
|
png: "",
|
|
52
52
|
width: null,
|
|
53
53
|
height: null,
|
|
54
|
-
connect: "
|
|
54
|
+
connect: "connecting",
|
|
55
55
|
};
|
|
56
56
|
|
|
57
57
|
broadcastState() {
|
|
@@ -74,7 +74,7 @@ export default class EmulatorPngView extends Component {
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
startStream() {
|
|
77
|
-
const { width, height,
|
|
77
|
+
const { width, height, connect } = this.state;
|
|
78
78
|
if (this.screen) {
|
|
79
79
|
this.screen.cancel();
|
|
80
80
|
}
|
|
@@ -87,30 +87,42 @@ export default class EmulatorPngView extends Component {
|
|
|
87
87
|
|
|
88
88
|
var self = this;
|
|
89
89
|
const { emulator, poll } = this.props;
|
|
90
|
-
if (poll &&
|
|
90
|
+
if (poll && connect !== "disconnected") {
|
|
91
91
|
emulator.getScreenshot(request, {}, (err, response) => {
|
|
92
92
|
this.setState({ connect: "connected" }, this.broadcastState);
|
|
93
93
|
// Update the image with the one we just received.
|
|
94
|
-
self.setState(
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
94
|
+
self.setState(
|
|
95
|
+
{
|
|
96
|
+
png: "data:image/jpeg;base64," + response.getImage_asB64(),
|
|
97
|
+
},
|
|
98
|
+
this.startStream
|
|
99
|
+
);
|
|
98
100
|
});
|
|
99
101
|
} else {
|
|
100
102
|
this.screen = emulator.streamScreenshot(request);
|
|
101
103
|
this.screen.on("data", (response) => {
|
|
102
|
-
|
|
104
|
+
self.setState({ connect: "connected" }, this.broadcastState);
|
|
103
105
|
// Update the image with the one we just received.
|
|
104
106
|
self.setState({
|
|
105
107
|
png: "data:image/jpeg;base64," + response.getImage_asB64(),
|
|
106
108
|
});
|
|
107
109
|
});
|
|
110
|
+
this.screen.on("error", (e) => {
|
|
111
|
+
console.warn("Screenshot stream broken", e)
|
|
112
|
+
const { connect } = this.state;
|
|
113
|
+
if (connect === "connected") {
|
|
114
|
+
console.log("Reconnecting..");
|
|
115
|
+
self.setState({ connect: "connecting" }, this.startStream);
|
|
116
|
+
} else {
|
|
117
|
+
self.setState({ connect: "disconnected" }, this.broadcastState);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
108
120
|
}
|
|
109
121
|
}
|
|
110
122
|
|
|
111
123
|
preventDragHandler = (e) => {
|
|
112
124
|
e.preventDefault();
|
|
113
|
-
}
|
|
125
|
+
};
|
|
114
126
|
|
|
115
127
|
render() {
|
|
116
128
|
const { width } = this.props;
|
|
@@ -124,19 +136,23 @@ export default class EmulatorPngView extends Component {
|
|
|
124
136
|
height: "100%",
|
|
125
137
|
objectFit: "contain",
|
|
126
138
|
objectPosition: "center",
|
|
127
|
-
|
|
128
139
|
}}
|
|
129
140
|
onDragStart={this.preventDragHandler}
|
|
130
141
|
>
|
|
131
142
|
<ResizeObserver
|
|
132
|
-
|
|
143
|
+
onReflow={(rect) => {
|
|
133
144
|
self.setState(
|
|
134
145
|
{ width: rect.width, height: rect.height },
|
|
135
146
|
self.startStream
|
|
136
147
|
);
|
|
137
148
|
}}
|
|
138
149
|
/>
|
|
139
|
-
<img
|
|
150
|
+
<img
|
|
151
|
+
src={this.state.png}
|
|
152
|
+
width="100%"
|
|
153
|
+
draggable="false"
|
|
154
|
+
style={{ pointerEvents: "none" }}
|
|
155
|
+
/>
|
|
140
156
|
</div>
|
|
141
157
|
);
|
|
142
158
|
}
|
|
@@ -17,9 +17,8 @@ import "@testing-library/jest-dom";
|
|
|
17
17
|
|
|
18
18
|
import React from "react";
|
|
19
19
|
import { render, fireEvent, screen } from "@testing-library/react";
|
|
20
|
+
import { fakeMouseEvent, fakeTouchEvent} from "./fake_events";
|
|
20
21
|
import withMouseKeyHandler from "../src/components/emulator/views/event_handler";
|
|
21
|
-
import * as Proto from "../src/proto/emulator_controller_pb";
|
|
22
|
-
import * as Rtc from "../src/proto/rtc_service_pb";
|
|
23
22
|
|
|
24
23
|
import JsepProtocol from "../src/components/emulator/net/jsep_protocol_driver";
|
|
25
24
|
import {
|
|
@@ -43,33 +42,6 @@ class FakeEmulator extends React.Component {
|
|
|
43
42
|
}
|
|
44
43
|
}
|
|
45
44
|
|
|
46
|
-
const fakeMouseEvent = (tp, x, y, props = {}) => {
|
|
47
|
-
const event = new MouseEvent(tp, {
|
|
48
|
-
bubbles: true,
|
|
49
|
-
cancelable: true,
|
|
50
|
-
...props,
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
Object.defineProperty(event, "offsetX", { get: () => x });
|
|
54
|
-
Object.defineProperty(event, "offsetY", { get: () => y });
|
|
55
|
-
return event;
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const fakeTouchEvent = (tp, x, y, force, props = {}) => {
|
|
59
|
-
const event = new TouchEvent(tp, {
|
|
60
|
-
bubbles: true,
|
|
61
|
-
cancelable: true,
|
|
62
|
-
...props,
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
Object.defineProperty(event, "changedTouches", {
|
|
66
|
-
get: () => [
|
|
67
|
-
{ clientX: x, clientY: y, radiusX: 4, radiusY: 4, force: force },
|
|
68
|
-
],
|
|
69
|
-
});
|
|
70
|
-
return event;
|
|
71
|
-
};
|
|
72
|
-
|
|
73
45
|
const TestView = withMouseKeyHandler(FakeEmulator);
|
|
74
46
|
describe("The event handler using a real jsep serializer", () => {
|
|
75
47
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2021 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
|
+
export function fakeMouseEvent(tp, x, y, props = {}) {
|
|
17
|
+
const event = new MouseEvent(tp, {
|
|
18
|
+
bubbles: true,
|
|
19
|
+
cancelable: true,
|
|
20
|
+
...props,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
Object.defineProperty(event, "offsetX", { get: () => x });
|
|
24
|
+
Object.defineProperty(event, "offsetY", { get: () => y });
|
|
25
|
+
return event;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function fakeTouchEvent(tp, x, y, force, props = {}) {
|
|
29
|
+
const event = new TouchEvent(tp, {
|
|
30
|
+
bubbles: true,
|
|
31
|
+
cancelable: true,
|
|
32
|
+
...props,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
Object.defineProperty(event, "changedTouches", {
|
|
36
|
+
get: () => [
|
|
37
|
+
{ clientX: x, clientY: y, radiusX: 4, radiusY: 4, force: force },
|
|
38
|
+
],
|
|
39
|
+
});
|
|
40
|
+
return event;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function resize(width, height) {
|
|
44
|
+
const resizeEvent = document.createEvent("Event");
|
|
45
|
+
resizeEvent.initEvent("resize", true, true);
|
|
46
|
+
|
|
47
|
+
global.window.innerWidth = width || global.window.innerWidth;
|
|
48
|
+
global.window.innerHeight = height || global.window.innerHeight;
|
|
49
|
+
global.window.dispatchEvent(resizeEvent);
|
|
50
|
+
}
|
|
@@ -18,7 +18,6 @@ import "regenerator-runtime/runtime"; // Somehow needed for jest to be happy wit
|
|
|
18
18
|
|
|
19
19
|
import * as Proto from "../src/proto/emulator_controller_pb";
|
|
20
20
|
import * as Rtc from "../src/proto/rtc_service_pb";
|
|
21
|
-
import { render, waitFor, screen } from "@testing-library/react";
|
|
22
21
|
import JsepProtocol from "../src/components/emulator/net/jsep_protocol_driver.js";
|
|
23
22
|
import {
|
|
24
23
|
RtcService,
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2021 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 { jest } from "@jest/globals";
|
|
17
|
+
import "regenerator-runtime/runtime"; // Somehow needed for jest to be happy with ES6
|
|
18
|
+
|
|
19
|
+
import * as Proto from "../src/proto/emulator_controller_pb";
|
|
20
|
+
import React from "react";
|
|
21
|
+
import EmulatorPngView from "../src/components/emulator/views/simple_png_view";
|
|
22
|
+
import { resize } from "./fake_events";
|
|
23
|
+
import { render, screen } from "@testing-library/react";
|
|
24
|
+
import { EmulatorControllerService } from "../src/proto/emulator_web_client";
|
|
25
|
+
import { EventEmitter } from "events";
|
|
26
|
+
|
|
27
|
+
jest.mock("../src/proto/emulator_web_client");
|
|
28
|
+
|
|
29
|
+
const googleLogo =
|
|
30
|
+
"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";
|
|
31
|
+
const googleImage = new Proto.Image();
|
|
32
|
+
googleImage.setImage(Uint8Array.from(atob(googleLogo), (c) => c.charCodeAt(0)));
|
|
33
|
+
|
|
34
|
+
const stream = new EventEmitter();
|
|
35
|
+
describe("A simple png view", () => {
|
|
36
|
+
EmulatorControllerService.mockImplementation(() => {
|
|
37
|
+
let count = 0;
|
|
38
|
+
return {
|
|
39
|
+
getScreenshot: jest.fn((a, b, response) => {
|
|
40
|
+
count++;
|
|
41
|
+
if (count < 2) response(null, googleImage);
|
|
42
|
+
}),
|
|
43
|
+
streamScreenshot: jest.fn((request) => {
|
|
44
|
+
stream.removeAllListeners();
|
|
45
|
+
return {
|
|
46
|
+
on: (name, fn) => {
|
|
47
|
+
stream.on(name, fn);
|
|
48
|
+
},
|
|
49
|
+
cancel: jest.fn(),
|
|
50
|
+
};
|
|
51
|
+
}),
|
|
52
|
+
getStatus: jest.fn(() => {}),
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
beforeEach(()=>{
|
|
57
|
+
stream.removeAllListeners();
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it("Get screenshot renders an image.", () => {
|
|
61
|
+
const emulatorServiceInstance = new EmulatorControllerService("http://foo");
|
|
62
|
+
const { container } = render(
|
|
63
|
+
<EmulatorPngView emulator={emulatorServiceInstance} poll={true} />
|
|
64
|
+
);
|
|
65
|
+
const pngView = container.querySelector("img");
|
|
66
|
+
expect(pngView.src).toBe("data:image/jpeg;base64," + googleLogo);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("A resize triggers a new stream request.", () => {
|
|
70
|
+
const emulatorServiceInstance = new EmulatorControllerService("http://foo");
|
|
71
|
+
render(
|
|
72
|
+
<div data-testid="pngdiv">
|
|
73
|
+
<EmulatorPngView emulator={emulatorServiceInstance} />
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
// Initial stream request + resize event after mount.
|
|
78
|
+
expect(emulatorServiceInstance.streamScreenshot).toHaveBeenCalledTimes(2);
|
|
79
|
+
|
|
80
|
+
let pngview = screen.getByTestId("pngdiv").childNodes[0];
|
|
81
|
+
pngview.getBoundingClientRect = jest.fn();
|
|
82
|
+
pngview.getBoundingClientRect.mockReturnValueOnce({
|
|
83
|
+
width: 120,
|
|
84
|
+
height: 120,
|
|
85
|
+
top: 0,
|
|
86
|
+
left: 0,
|
|
87
|
+
bottom: 0,
|
|
88
|
+
right: 0,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// A resize triggers a new stream request.
|
|
92
|
+
resize(200, 300);
|
|
93
|
+
expect(emulatorServiceInstance.streamScreenshot).toHaveBeenCalledTimes(3);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
it("Has a connected state after the first image arrives", () => {
|
|
98
|
+
const emulatorServiceInstance = new EmulatorControllerService("http://foo");
|
|
99
|
+
const changeState = jest.fn()
|
|
100
|
+
render(<EmulatorPngView emulator={emulatorServiceInstance} onStateChange={changeState}/>);
|
|
101
|
+
expect(changeState).toHaveBeenCalledWith("connecting");
|
|
102
|
+
stream.emit("data", googleImage);
|
|
103
|
+
expect(changeState).toHaveBeenCalledWith("connected");
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("Attempts to reconnect if the server disconnects", () => {
|
|
107
|
+
const emulatorServiceInstance = new EmulatorControllerService("http://foo");
|
|
108
|
+
render(<EmulatorPngView emulator={emulatorServiceInstance} />);
|
|
109
|
+
expect(emulatorServiceInstance.streamScreenshot).toHaveBeenCalledTimes(2);
|
|
110
|
+
stream.emit("data", googleImage);
|
|
111
|
+
stream.emit("error", "fda");
|
|
112
|
+
expect(emulatorServiceInstance.streamScreenshot).toHaveBeenCalledTimes(3);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("Gives up on the second failure.", () => {
|
|
116
|
+
const emulatorServiceInstance = new EmulatorControllerService("http://foo");
|
|
117
|
+
const changeState = jest.fn()
|
|
118
|
+
render(<EmulatorPngView emulator={emulatorServiceInstance} onStateChange={changeState}/>);
|
|
119
|
+
expect(emulatorServiceInstance.streamScreenshot).toHaveBeenCalledTimes(2);
|
|
120
|
+
|
|
121
|
+
// Connect
|
|
122
|
+
stream.emit("data", googleImage);
|
|
123
|
+
|
|
124
|
+
// First break, we attempt a reconnect.
|
|
125
|
+
stream.emit("error", "fda");
|
|
126
|
+
expect(emulatorServiceInstance.streamScreenshot).toHaveBeenCalledTimes(3);
|
|
127
|
+
expect(changeState).not.toHaveBeenCalledWith("disconnected");
|
|
128
|
+
|
|
129
|
+
// We could not reconnect, so we fail.
|
|
130
|
+
stream.emit("error", "fda");
|
|
131
|
+
expect(changeState).toHaveBeenCalledWith("disconnected");
|
|
132
|
+
});
|
|
133
|
+
});
|