UNPKG

23.4 kBJavaScriptView Raw
1"use strict";
2var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4 return new (P || (P = Promise))(function (resolve, reject) {
5 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7 function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8 step((generator = generator.apply(thisArg, _arguments || [])).next());
9 });
10};
11var __generator = (this && this.__generator) || function (thisArg, body) {
12 var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13 return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14 function verb(n) { return function (v) { return step([n, v]); }; }
15 function step(op) {
16 if (f) throw new TypeError("Generator is already executing.");
17 while (g && (g = 0, op[0] && (_ = 0)), _) try {
18 if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19 if (y = 0, t) op = [op[0] & 2, t.value];
20 switch (op[0]) {
21 case 0: case 1: t = op; break;
22 case 4: _.label++; return { value: op[1], done: false };
23 case 5: _.label++; y = op[1]; op = [0]; continue;
24 case 7: op = _.ops.pop(); _.trys.pop(); continue;
25 default:
26 if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27 if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28 if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29 if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30 if (t[2]) _.ops.pop();
31 _.trys.pop(); continue;
32 }
33 op = body.call(thisArg, _);
34 } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35 if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36 }
37};
38Object.defineProperty(exports, "__esModule", { value: true });
39exports.Device = exports.DeviceEmitter = void 0;
40var events_1 = require("events");
41var utils_1 = require("./utils");
42var DeviceEmitter = /** @class */ (function () {
43 function DeviceEmitter() {
44 this.emitter = new events_1.EventEmitter();
45 }
46 DeviceEmitter.prototype.on = function (eventName, listener) {
47 this.emitter.on(eventName, listener);
48 };
49 DeviceEmitter.prototype.off = function (eventName, listener) {
50 this.emitter.off(eventName, listener);
51 };
52 DeviceEmitter.prototype.emit = function (eventName, arg) {
53 this.emitter.emit(eventName, arg);
54 };
55 return DeviceEmitter;
56}());
57exports.DeviceEmitter = DeviceEmitter;
58/**
59 * The Device instance is binding with specific serial number of adb device.
60 *
61 */
62var Device = /** @class */ (function () {
63 function Device(adbPath, serialNumber, connectStatus) {
64 /**
65 * Check whether device is connected before issue a command
66 */
67 this.autoCheckConnected = true;
68 this.deviceResolution = { x: 0, y: 0 };
69 this.commandResolution = { x: 1280, y: 720 };
70 this._running = false;
71 this._eventEmmiter = new DeviceEmitter();
72 this.adbPath = adbPath;
73 this.serialNumber = serialNumber;
74 this._connected = connectStatus;
75 }
76 Object.defineProperty(Device.prototype, "resolutionRatio", {
77 get: function () {
78 return {
79 x: this.deviceResolution.x / this.commandResolution.x,
80 y: this.deviceResolution.y / this.commandResolution.y,
81 };
82 },
83 enumerable: false,
84 configurable: true
85 });
86 Object.defineProperty(Device.prototype, "connected", {
87 /**
88 * Determines whether the device is connected
89 */
90 get: function () {
91 return this._connected;
92 },
93 enumerable: false,
94 configurable: true
95 });
96 Object.defineProperty(Device.prototype, "running", {
97 /**
98 * Determines whether the command is running
99 */
100 get: function () {
101 return this._running;
102 },
103 enumerable: false,
104 configurable: true
105 });
106 Device.prototype.checkConnected = function () {
107 return __awaiter(this, arguments, void 0, function (retry) {
108 var i, devicesStdout, deviceInfoArray, devicesAttached, _i, deviceInfoArray_1, info, _a, serialNumber, connectStatus;
109 if (retry === void 0) { retry = 3; }
110 return __generator(this, function (_b) {
111 switch (_b.label) {
112 case 0:
113 i = 0;
114 _b.label = 1;
115 case 1:
116 if (!(i < retry)) return [3 /*break*/, 6];
117 return [4 /*yield*/, (0, utils_1.issueCommand)({ adbPath: this.adbPath, args: ["devices"] })];
118 case 2:
119 devicesStdout = _b.sent();
120 deviceInfoArray = devicesStdout.trim().split("\r\n");
121 devicesAttached = false;
122 for (_i = 0, deviceInfoArray_1 = deviceInfoArray; _i < deviceInfoArray_1.length; _i++) {
123 info = deviceInfoArray_1[_i];
124 if (devicesAttached) {
125 _a = info.split("\t"), serialNumber = _a[0], connectStatus = _a[1];
126 if (serialNumber === this.serialNumber) {
127 return [2 /*return*/, connectStatus === "device"];
128 }
129 }
130 else if (info === "List of devices attached") {
131 devicesAttached = true;
132 }
133 }
134 if (!(i < retry - 1)) return [3 /*break*/, 4];
135 return [4 /*yield*/, (0, utils_1.delay)(3000)];
136 case 3:
137 _b.sent();
138 return [3 /*break*/, 5];
139 case 4:
140 console.log("Adb get devices failed");
141 _b.label = 5;
142 case 5:
143 i++;
144 return [3 /*break*/, 1];
145 case 6: return [2 /*return*/, false];
146 }
147 });
148 });
149 };
150 /**
151 * Issue command by text
152 * @param commandText
153 */
154 Device.prototype.issueShellCommandText = function (commandText) {
155 return __awaiter(this, void 0, void 0, function () {
156 var _a, result;
157 return __generator(this, function (_b) {
158 switch (_b.label) {
159 case 0:
160 if (!this.autoCheckConnected) return [3 /*break*/, 2];
161 _a = this;
162 return [4 /*yield*/, this.checkConnected()];
163 case 1:
164 _a._connected = _b.sent();
165 _b.label = 2;
166 case 2:
167 if (!this._connected)
168 return [2 /*return*/, ""];
169 this._running = true;
170 return [4 /*yield*/, (0, utils_1.issueCommand)({
171 adbPath: this.adbPath,
172 serialNumber: this.serialNumber,
173 isShellCommand: true,
174 args: commandText.split(" "),
175 })];
176 case 3:
177 result = _b.sent();
178 this._running = false;
179 return [2 /*return*/, result];
180 }
181 });
182 });
183 };
184 /**
185 * Issue specified command
186 * @param command
187 */
188 Device.prototype.issueShellCommand = function (command) {
189 return __awaiter(this, void 0, void 0, function () {
190 var _a;
191 return __generator(this, function (_b) {
192 switch (_b.label) {
193 case 0:
194 if (!this.autoCheckConnected) return [3 /*break*/, 2];
195 _a = this;
196 return [4 /*yield*/, this.checkConnected()];
197 case 1:
198 _a._connected = _b.sent();
199 _b.label = 2;
200 case 2:
201 if (!this._connected)
202 return [2 /*return*/, false];
203 this._running = true;
204 this._eventEmmiter.emit("command_start", command);
205 return [4 /*yield*/, (0, utils_1.delay)(command.preDelay)];
206 case 3:
207 _b.sent();
208 return [4 /*yield*/, (0, utils_1.issueCommand)({
209 adbPath: this.adbPath,
210 serialNumber: this.serialNumber,
211 isShellCommand: true,
212 args: command.getCommandArgs(this.resolutionRatio),
213 })];
214 case 4:
215 _b.sent();
216 return [4 /*yield*/, (0, utils_1.delay)(command.postDelay)];
217 case 5:
218 _b.sent();
219 this._eventEmmiter.emit("command_finish", command);
220 this._running = false;
221 return [2 /*return*/, true];
222 }
223 });
224 });
225 };
226 /**
227 * Issue specified commands
228 * @param commands
229 */
230 Device.prototype.issueShellCommands = function (commands) {
231 return __awaiter(this, void 0, void 0, function () {
232 var _i, commands_1, command, status;
233 return __generator(this, function (_a) {
234 switch (_a.label) {
235 case 0:
236 _i = 0, commands_1 = commands;
237 _a.label = 1;
238 case 1:
239 if (!(_i < commands_1.length)) return [3 /*break*/, 4];
240 command = commands_1[_i];
241 return [4 /*yield*/, this.issueShellCommand(command)];
242 case 2:
243 status = _a.sent();
244 if (!status)
245 return [2 /*return*/, false];
246 _a.label = 3;
247 case 3:
248 _i++;
249 return [3 /*break*/, 1];
250 case 4: return [2 /*return*/, true];
251 }
252 });
253 });
254 };
255 /**
256 * Add listener to command life cycle event
257 * @param eventName
258 * @param listener
259 */
260 Device.prototype.on = function (eventName, listener) {
261 this._eventEmmiter.on(eventName, listener);
262 };
263 /**
264 * Remove Listener to command life cycle event
265 * @param eventName
266 * @param listener
267 */
268 Device.prototype.off = function (eventName, listener) {
269 this._eventEmmiter.off(eventName, listener);
270 };
271 /**
272 * Get resolution of this device
273 * @returns
274 */
275 Device.prototype.getResolution = function () {
276 return __awaiter(this, void 0, void 0, function () {
277 var result, _a, width, height;
278 return __generator(this, function (_b) {
279 switch (_b.label) {
280 case 0: return [4 /*yield*/, this.issueShellCommandText("wm size")];
281 case 1:
282 result = _b.sent();
283 _a = result.split(":")[1].split("x"), width = _a[0], height = _a[1];
284 return [2 /*return*/, { x: Number(width.trim()), y: Number(height.trim()) }];
285 }
286 });
287 });
288 };
289 Device.prototype.getAllPackages = function () {
290 return __awaiter(this, void 0, void 0, function () {
291 var result, packages;
292 return __generator(this, function (_a) {
293 switch (_a.label) {
294 case 0: return [4 /*yield*/, this.issueShellCommandText("pm list packages")];
295 case 1:
296 result = _a.sent();
297 packages = this.parsePackages(result);
298 return [2 /*return*/, packages];
299 }
300 });
301 });
302 };
303 Device.prototype.getSystemPackages = function () {
304 return __awaiter(this, void 0, void 0, function () {
305 var result, packages;
306 return __generator(this, function (_a) {
307 switch (_a.label) {
308 case 0: return [4 /*yield*/, this.issueShellCommandText("pm list packages -s")];
309 case 1:
310 result = _a.sent();
311 packages = this.parsePackages(result);
312 return [2 /*return*/, packages];
313 }
314 });
315 });
316 };
317 Device.prototype.getThirdPartyPackages = function () {
318 return __awaiter(this, void 0, void 0, function () {
319 var result, packages;
320 return __generator(this, function (_a) {
321 switch (_a.label) {
322 case 0: return [4 /*yield*/, this.issueShellCommandText("pm list packages -3")];
323 case 1:
324 result = _a.sent();
325 packages = this.parsePackages(result);
326 return [2 /*return*/, packages];
327 }
328 });
329 });
330 };
331 Device.prototype.parsePackages = function (content) {
332 var lines = content.split("\r\n");
333 var packages = [];
334 for (var _i = 0, lines_1 = lines; _i < lines_1.length; _i++) {
335 var l = lines_1[_i];
336 if (l === "")
337 continue;
338 packages.push(l.split(":")[1]);
339 }
340 return packages;
341 };
342 Device.prototype.existPackage = function (packageName) {
343 return __awaiter(this, void 0, void 0, function () {
344 var packages;
345 return __generator(this, function (_a) {
346 switch (_a.label) {
347 case 0: return [4 /*yield*/, this.getAllPackages()];
348 case 1:
349 packages = _a.sent();
350 return [2 /*return*/, packages.includes(packageName)];
351 }
352 });
353 });
354 };
355 /**
356 * Check if activity is running top
357 * @param activityName
358 * @returns
359 */
360 Device.prototype.isCurrentActivity = function (packageName, activityName) {
361 return __awaiter(this, void 0, void 0, function () {
362 var result, resultLines, _i, resultLines_1, line;
363 return __generator(this, function (_a) {
364 switch (_a.label) {
365 case 0: return [4 /*yield*/, this.issueShellCommandText("dumpsys window")];
366 case 1:
367 result = _a.sent();
368 resultLines = result.split("\r\n");
369 for (_i = 0, resultLines_1 = resultLines; _i < resultLines_1.length; _i++) {
370 line = resultLines_1[_i];
371 if (!line.includes("mCurrentFocus"))
372 continue;
373 if (activityName) {
374 if (line.includes("".concat(packageName, "/").concat(activityName)))
375 return [2 /*return*/, true];
376 }
377 else {
378 if (line.includes(packageName))
379 return [2 /*return*/, true];
380 }
381 }
382 return [2 /*return*/, false];
383 }
384 });
385 });
386 };
387 /**
388 * Start an app if not at the current focus
389 * @param packageName
390 * @param activityName
391 */
392 Device.prototype.startApp = function (packageName_1, activityName_1) {
393 return __awaiter(this, arguments, void 0, function (packageName, activityName, timeout) {
394 var _this = this;
395 if (timeout === void 0) { timeout = 10000; }
396 return __generator(this, function (_a) {
397 switch (_a.label) {
398 case 0: return [4 /*yield*/, this.issueShellCommandText("am start -n ".concat(packageName, "/").concat(activityName))];
399 case 1:
400 _a.sent();
401 return [2 /*return*/, new Promise(function (resolve) { return __awaiter(_this, void 0, void 0, function () {
402 var retry, interval;
403 var _this = this;
404 return __generator(this, function (_a) {
405 retry = 0;
406 interval = setInterval(function () { return __awaiter(_this, void 0, void 0, function () {
407 var status;
408 return __generator(this, function (_a) {
409 switch (_a.label) {
410 case 0:
411 if (!(retry * 1000 >= timeout)) return [3 /*break*/, 1];
412 clearInterval(interval);
413 resolve(false);
414 return [3 /*break*/, 3];
415 case 1: return [4 /*yield*/, this.isCurrentActivity("".concat(packageName, "/").concat(activityName))];
416 case 2:
417 status = _a.sent();
418 if (status) {
419 clearInterval(interval);
420 resolve(true);
421 }
422 else {
423 retry++;
424 }
425 _a.label = 3;
426 case 3: return [2 /*return*/];
427 }
428 });
429 }); });
430 return [2 /*return*/];
431 });
432 }); })];
433 }
434 });
435 });
436 };
437 /**
438 * Close an app
439 * @param packageName
440 */
441 Device.prototype.closeApp = function (packageName_1) {
442 return __awaiter(this, arguments, void 0, function (packageName, timeout) {
443 var _this = this;
444 if (timeout === void 0) { timeout = 10000; }
445 return __generator(this, function (_a) {
446 switch (_a.label) {
447 case 0: return [4 /*yield*/, this.issueShellCommandText("am force-stop ".concat(packageName))];
448 case 1:
449 _a.sent();
450 return [2 /*return*/, new Promise(function (resolve) { return __awaiter(_this, void 0, void 0, function () {
451 var retry, interval;
452 var _this = this;
453 return __generator(this, function (_a) {
454 retry = 0;
455 interval = setInterval(function () { return __awaiter(_this, void 0, void 0, function () {
456 var status;
457 return __generator(this, function (_a) {
458 switch (_a.label) {
459 case 0:
460 if (!(retry * 1000 >= timeout)) return [3 /*break*/, 1];
461 clearInterval(interval);
462 resolve(false);
463 return [3 /*break*/, 3];
464 case 1: return [4 /*yield*/, this.isCurrentActivity(packageName)];
465 case 2:
466 status = _a.sent();
467 if (status) {
468 retry++;
469 }
470 else {
471 clearInterval(interval);
472 resolve(true);
473 }
474 _a.label = 3;
475 case 3: return [2 /*return*/];
476 }
477 });
478 }); });
479 return [2 /*return*/];
480 });
481 }); })];
482 }
483 });
484 });
485 };
486 /**
487 * Take a screencap and pull it out
488 * @param options
489 */
490 Device.prototype.getScreencap = function (options) {
491 return __awaiter(this, void 0, void 0, function () {
492 return __generator(this, function (_a) {
493 switch (_a.label) {
494 case 0: return [4 /*yield*/, this.issueShellCommandText("screencap ".concat((options === null || options === void 0 ? void 0 : options.fileName) || "/sdcard/screen.png"))];
495 case 1:
496 _a.sent();
497 return [4 /*yield*/, this.issueShellCommandText("pull ".concat((options === null || options === void 0 ? void 0 : options.fileName) || "/sdcard/screen.png", " ").concat((options === null || options === void 0 ? void 0 : options.pullPath) || "./"))];
498 case 2:
499 _a.sent();
500 return [2 /*return*/];
501 }
502 });
503 });
504 };
505 return Device;
506}());
507exports.Device = Device;