var util = require('util') var Promise = require('bluebird') var ProtoBuf = require('protobufjs') var ByteBuffer = require('protobufjs/node_modules/bytebuffer') var semver = require('semver') var pathutil = require('../util/pathutil') var streamutil = require('../util/streamutil') var SUPPORTED_VERSION = '~0.1.2'; var pkg = 'jp.co.cyberagent.stf.input.agent' var apk = pathutil.vendor('InputAgent/InputAgent.apk') var proto = ProtoBuf.loadProtoFile( pathutil.vendor('InputAgent/proto/agent.proto') ).build().jp.co.cyberagent.stf.input.agent.proto var inputAgent = module.exports = Object.create(null) function IncompatibleVersionError(version) { Error.call(this, util.format('Incompatible version %s', version)) this.name = 'IncompatibleVersionError' this.version = version Error.captureStackTrace(this, IncompatibleVersionError) } util.inherits(IncompatibleVersionError, Error) inputAgent.IncompatibleVersionError = IncompatibleVersionError inputAgent.getInstalledPath = function(adb, serial) { return adb.shellAsync(serial, util.format("pm path '%s'", pkg)) .then(function(out) { return streamutil.findLine(out, (/^package:/)) .then(function(line) { return line.substr(8) }) }) } inputAgent.ensureInstalled = function(adb, serial) { return inputAgent.getInstalledPath(adb, serial) .then(function(installedPath) { return adb.shellAsync(serial, util.format( "export CLASSPATH='%s';" + ' exec app_process /system/bin' + ' jp.co.cyberagent.stf.input.agent.InputAgent --version' , installedPath )) .then(function(out) { return streamutil.readAll(out) .then(function(buffer) { var version = buffer.toString() if (semver.satisfies(version, SUPPORTED_VERSION)) { return installedPath } else { return Promise.reject(new IncompatibleVersionError(version)) } }) }) }) .catch(function() { return adb.installAsync(serial, apk) .then(function() { return inputAgent.getInstalledPath(adb, serial) }) }) } inputAgent.openAgent = function(adb, serial) { return inputAgent.ensureInstalled(adb, serial) .then(function(installedPath) { return adb.shellAsync(serial, util.format( "export CLASSPATH='%s';" + ' exec app_process /system/bin' + ' jp.co.cyberagent.stf.input.agent.InputAgent' , installedPath )) }) } inputAgent.openService = function(adb, serial) { return inputAgent.ensureInstalled(adb, serial) .then(function() { var intent = '-a jp.co.cyberagent.stf.input.agent.InputService.ACTION_START' return adb.shellAsync(serial, util.format( 'am startservice --user 0 %s || am startservice %s' , intent , intent )) }) } inputAgent.stopService = function(adb, serial) { var intent = '-a jp.co.cyberagent.stf.input.agent.InputService.ACTION_STOP' return adb.shellAsync(serial, util.format( 'am startservice --user 0 %s || am startservice %s' , intent , intent )) } inputAgent.sendInputEvent = function(agent, event) { var lengthBuffer = new ByteBuffer() , messageBuffer = new proto.InputEvent(event).encode() lengthBuffer.writeVarint32(messageBuffer.length) agent.write(Buffer.concat([ lengthBuffer.toBuffer() , messageBuffer.toBuffer() ])) } inputAgent.unlock = function(service) { service.write('unlock\n'); } inputAgent.lock = function(service) { service.write('lock\n'); } inputAgent.acquireWakeLock = function(service) { service.write('acquire wake lock\n'); } inputAgent.releaseWakeLock = function(service) { service.write('release wake lock\n'); } inputAgent.identity = function(service, serial) { service.write(util.format('show identity %s\n', serial)); }