class DeviceAPI::Android::ADB

Namespace for all methods encapsulating adb calls

Public Class Methods

am(qualifier, command) click to toggle source

Starts intent using adb Returns stdout @param qualifier qualifier of device @param command -option activity @example DeviceAPI::ADB.am(qualifier, “start -a android.intent.action.MAIN -n com.android.settings/.wifi.WifiSettings”)

# File lib/device_api/android/adb.rb, line 341
def self.am(qualifier, command)
  shell(qualifier, "am #{command}").stdout
end
block_package(qualifier, package) click to toggle source

Blocks a package, used on Android versions less than KitKat Returns boolean @param qualifier qualifier of device @param package to block

# File lib/device_api/android/adb.rb, line 357
def self.block_package(qualifier, package)
  result = pm(qualifier, "block #{package}")
  result.include?('true')
end
change_apk(options = {}) click to toggle source
# File lib/device_api/android/adb.rb, line 149
def self.change_apk(options = {})
  package_name = options[:package_name]
  apk = options[:apk]
  qualifier = options[:qualifier]
  action = options[:action]

  case action
    when :install
      command = "adb -s #{qualifier} install #{apk}"
    when :uninstall
      command = "adb -s #{qualifier} uninstall #{package_name}"
    else
      raise ADBCommandError.new('No action specified')
  end

  result = execute(command)

  raise ADBCommandError.new(result.stderr) if result.exit != 0

  lines = result.stdout.split("\n").map { |line| line.strip }

  lines.last
end
check_ip_address(ip_address_and_port) click to toggle source
# File lib/device_api/android/adb.rb, line 371
def self.check_ip_address(ip_address_and_port)
  unless ip_address_and_port =~ /\A(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3}):[0-9]+\Z/ 
       raise ADBCommandError.new("Invalid IP address and port #{ip_address_and_port}")
  end
end
connect(ip_address, port=5555) click to toggle source

Connects to remote android device @param [String] ip_address @param [String] port @example

DeviceAPI::ADB.connect(ip_address, port)
# File lib/device_api/android/adb.rb, line 255
def self.connect(ip_address, port=5555)
  ip_address_and_port = "#{ip_address}:#{port}"
  check_ip_address(ip_address_and_port)
  cmd = "adb connect #{ip_address_and_port}"
  result = execute(cmd)
  if result.stdout.to_s =~ /.*already connected to.*/
    raise DeviceAlreadyConnectedError.new("Device #{ip_address_and_port} already connected")
  else 
    unless result.stdout.to_s =~ /.*connected to.*/
      raise ADBCommandError.new("Unable to adb connect to #{ip_address_and_port} result was: #{result.stdout}")
    end
  end 
end
devices() click to toggle source

Returns an array representing connected devices DeviceAPI::ADB.devices #=> { '1232132' => 'device' } @return (Array) list of attached devices

# File lib/device_api/android/adb.rb, line 17
def self.devices
  result = execute_with_timeout_and_retry('adb devices')

  raise ADBCommandError.new(result.stderr) if result.exit != 0
  result.stdout.scan(/(.*)\t(.*)/).map { |a,b| {a => b}}
end
disconnect(ip_address, port=5555) click to toggle source

Disconnects from remote android device @param [String] ip_address @param [String] port @example

DeviceAPI::ADB.disconnect(ip_address, port)
# File lib/device_api/android/adb.rb, line 274
def self.disconnect(ip_address, port=5555)
  ip_address_and_port = "#{ip_address}:#{port}"
  check_ip_address(ip_address_and_port)
  cmd = "adb disconnect #{ip_address_and_port}"
  result = execute(cmd)
  unless result.exit == 0
    raise ADBCommandError.new("Unable to adb disconnect to #{ip_address_and_port} result was: #{result.stdout}")
  end
end
dumpsys(qualifier, command) click to toggle source

Returns the 'dumpsys' information from the specified device @param qualifier qualifier of device @return (Array) array of results from adb shell dumpsys

# File lib/device_api/android/adb.rb, line 124
def self.dumpsys(qualifier, command)
  result = shell(qualifier, "dumpsys #{command}")
  result.stdout.split("\n").map { |line| line.strip }
end
get_battery_info(qualifier) click to toggle source

Get the 'battery' information from dumpsys @param [String] qualifier qualifier of device @return [Hash] hash containing battery information from dumpsys

# File lib/device_api/android/adb.rb, line 67
def self.get_battery_info(qualifier)
  lines = dumpsys(qualifier, 'battery')
  process_dumpsys('(.*):\s+(.*)', lines)
end
get_device_dpi(qualifier) click to toggle source
# File lib/device_api/android/adb.rb, line 110
def self.get_device_dpi(qualifier)
  lines = dumpsys(qualifier, 'window')
  dpi = nil
  lines.each do |line|
    if /sw(\d*)dp/.match(line)
      dpi = Regexp.last_match[1]
    end
  end
  dpi
end
get_network_info(qualifier) click to toggle source

Get the network information

# File lib/device_api/android/adb.rb, line 78
def self.get_network_info(qualifier)
  lines = shell(qualifier, 'netcfg')
  lines.stdout.split("\n").map do |a|
    b = a.split(" ")
    { name: b[0], ip: b[2].split('/')[0], mac: b[4] }
  end
end
get_network_interface(qualifier, interface) click to toggle source
# File lib/device_api/android/adb.rb, line 72
def self.get_network_interface(qualifier, interface)
  result = shell(qualifier, "ifconfig #{interface}")
  result.stdout
end
get_state(qualifier) click to toggle source

Retrieve device state for a single device @param qualifier qualifier of device @return (String) device state

# File lib/device_api/android/adb.rb, line 27
def self.get_state(qualifier)
  result = execute('adb -s #{qualifier} get-state')

  raise ADBCommandError.new(result.stderr) if result.exit != 0

  lines = result.stdout.split("\n")
  /(.*)/.match(lines.last)
  Regexp.last_match[0].strip
end
get_uptime(qualifier) click to toggle source

Returns the uptime of the specified device @param qualifier qualifier of device @return (Float) uptime in seconds

# File lib/device_api/android/adb.rb, line 176
def self.get_uptime(qualifier)
  result = shell(qualifier, 'cat /proc/uptime')

  lines = result.stdout.split("\n")
  uptime = 0
  lines.each do |l|
    if /([\d.]*)\s+[\d.]*/.match(l)
      uptime = Regexp.last_match[0].to_f.round
    end
  end
  uptime
end
getdumpsys(qualifier) click to toggle source

Get the 'input' information from dumpsys @param qualifier qualifier of device @return (Hash) hash containing input information from dumpsys

# File lib/device_api/android/adb.rb, line 51
def self.getdumpsys(qualifier)
  lines = dumpsys(qualifier, 'input')
  process_dumpsys('(.*):\s+(.*)', lines)
end
getphoneinfo(qualifier) click to toggle source

Get the 'iphonesubinfo' from dumpsys @param qualifier qualifier of device @return (Hash) hash containing iphonesubinfo information from dumpsys

# File lib/device_api/android/adb.rb, line 59
def self.getphoneinfo(qualifier)
  lines = dumpsys(qualifier, 'iphonesubinfo')
  process_dumpsys('(.*) =\s+(.*)', lines)
end
getpowerinfo(qualifier) click to toggle source

Get the 'power' information from dumpsys @param [String] qualifier qualifier of device @return [Hash] hash containing power information from dumpsys

# File lib/device_api/android/adb.rb, line 105
def self.getpowerinfo(qualifier)
  lines = dumpsys(qualifier, 'power')
  process_dumpsys('(.*)=(.*)', lines)
end
getprop(qualifier) click to toggle source

Get the properties of a specified device @param qualifier qualifier of device @return (Hash) hash containing device properties

# File lib/device_api/android/adb.rb, line 40
def self.getprop(qualifier)
  result = shell(qualifier, 'getprop')

  lines = result.stdout.encode('UTF-16', 'UTF-8', invalid: :replace, replace: '').encode('UTF-8', 'UTF-16').split("\n")

  process_dumpsys('\[(.*)\]:\s+\[(.*)\]', lines)
end
hide_package(qualifier, package) click to toggle source

Blocks a package on KitKat and above Returns boolean @param qualifier qualifier of device @param package to hide

# File lib/device_api/android/adb.rb, line 366
def self.hide_package(qualifier, package)
  result = pm(qualifier, "hide #{package}")
  result.include?('true')
end
install_apk(options = {}) click to toggle source

Installs a specified apk to a specific device @param [Hash] options the options used for installing an apk @option options [String] :apk path to apk to install @option options [String] :qualifier qualifier of device @return (String) return result from adb install command

# File lib/device_api/android/adb.rb, line 134
def self.install_apk(options = {})
  options[:action] = :install
  change_apk(options)
end
keyevent(qualifier, keyevent) click to toggle source

Sends a key event to the specified device @param [String] qualifier qualifier of device @param [String] keyevent keyevent to send to the device

# File lib/device_api/android/adb.rb, line 297
def self.keyevent(qualifier, keyevent)
  shell(qualifier, "input keyevent #{keyevent}").stdout
end
monkey(qualifier, args) click to toggle source

Runs monkey testing @param qualifier qualifier of device @param [Hash] args hash of arguments used for starting testing @option args [String] :events (10000) number of events to run @option args [String] :package name of package to run the tests against @option args [String] :seed pass the seed number (optional) @option args [String] :throttle throttle value (optional) @example

DeviceAPI::ADB.monkey( qualifier, :package => 'my.lovely.app' )
# File lib/device_api/android/adb.rb, line 216
def self.monkey(qualifier, args)

  events = args[:events] || 10000
  package = args[:package] or raise "package name not provided (:package => 'bbc.iplayer')"
  seed = args[:seed]
  throttle = args[:throttle]

  cmd = "monkey -p #{package} -v #{events}"
  cmd = cmd + " -s #{seed}" if seed
  cmd = cmd + " -t #{throttle}" if throttle

  shell(qualifier, cmd)
end
pm(qualifier, command) click to toggle source

Package manager commands @param qualifier qualifier of device @param command command to issue to the package manager @example DeviceAPI::ADB.pm(qualifier, 'list packages')

# File lib/device_api/android/adb.rb, line 349
def self.pm(qualifier, command)
  shell(qualifier, "pm #{command}").stdout
end
process_dumpsys(regex_string, data) click to toggle source

Processes the results from dumpsys to format them into a hash @param [String] regex_string regex string used to separate the results from the keys @param [Array] data data returned from dumpsys @return [Hash] hash containing the keys and values as distinguished by the supplied regex

# File lib/device_api/android/adb.rb, line 90
def self.process_dumpsys(regex_string, data)
  props = {}
  regex = Regexp.new(regex_string)
  data.each do |line|
    if regex.match(line)
      props[Regexp.last_match[1]] = Regexp.last_match[2]
    end
  end

  props
end
reboot(qualifier, remote) click to toggle source

Reboots the specified device Remote devices are rebooted and disconnected from system @param qualifier qualifier of device @return (nil) Nil if successful, otherwise an error is raised

# File lib/device_api/android/adb.rb, line 193
def self.reboot(qualifier, remote)
  if remote
    begin
      system("adb -s #{qualifier} reboot &")
      self.disconnect(qualifier.split(":").first)
    rescue => e
      raise ADBCommandError.new(e)
    end
  else
    result = execute("adb -s #{qualifier} reboot && adb -s #{qualifier} wait-for-device shell 'while [[ $(getprop dev.bootcomplete | tr -d '\r') != 1 ]    ]; do sleep 1; printf .; done'")
    raise ADBCommandError.new(result.stderr) if result.exit != 0
  end
end
screencap( qualifier, args ) click to toggle source

Take a screenshot from the device @param qualifier qualifier of device @param [Hash] args hash of arguments @option args [String] :filename name (with full path) required to save the image @example

DeviceAPI::ADB.screenshot( qualifier, :filename => '/tmp/filename.png' )
# File lib/device_api/android/adb.rb, line 236
def self.screencap( qualifier, args )
  
  filename = args[:filename] or raise "filename not provided (:filename => '/tmp/myfile.png')"
  
  if getprop(qualifier)['ro.build.version.release'].to_i < 7
    convert_carriage_returns = %q{perl -pe 's/\x0D\x0A/\x0A/g'} 
    cmd = "screencap -p | #{convert_carriage_returns} > #{filename}"
  else
    cmd = "screencap -p > #{filename}"
  end

  shell(qualifier, cmd)
end
shell(qualifier, command) click to toggle source

ADB Shell command @param [String] qualifier qualifier of device @param [String] command command to execute

# File lib/device_api/android/adb.rb, line 304
def self.shell(qualifier, command)
  result = execute("adb -s '#{qualifier}' shell #{command}")
  case result.stderr
  when /^error: device unauthorized./
    raise DeviceAPI::UnauthorizedDevice, result.stderr
  when /^error: device not found/
    raise DeviceAPI::DeviceNotFound, result.stderr
  # ADB.get_network_info on android > 7 behave differently
  #   On linux exit code is 127
  #   On MAC exit code is 0
  # Caught here to give get_network_info consistent response
  when /^\/system\/bin\/sh: netcfg: not found/
    return result
  else
    raise ADBCommandError.new(result.stderr)
  end if result.exit != 0

  result
end
swipe(qualifier, coords = {x_from: 0, y_from: 0, x_to: 0, y_to: 0 }) click to toggle source

Sends a swipe command to the specified device @param [String] qualifier qualifier of the device @param [Hash] coords hash of coordinates to swipe from / to @option coords [String] :x_from (0) Coordinate to start from on the X axis @option coords [String] :x_to (0) Coordinate to end on on the X axis @option coords [String] :y_from (0) Coordinate to start from on the Y axis @option coords [String] :y_to (0) Coordinate to end on on the Y axis

# File lib/device_api/android/adb.rb, line 331
def self.swipe(qualifier, coords = {x_from: 0, y_from: 0, x_to: 0, y_to: 0 })
  shell(qualifier, "input swipe #{coords[:x_from]} #{coords[:y_from]} #{coords[:x_to]} #{coords[:y_to]}").stdout
end
uninstall_apk(options = {}) click to toggle source

Uninstalls a specified package from a specified device @param [Hash] options the options used for uninstalling a package @option options [String] :package_name package to uninstall @option options [String] :qualifier qualifier of device @return (String) return result from adb uninstall command

# File lib/device_api/android/adb.rb, line 144
def self.uninstall_apk(options = {})
  options[:action] = :uninstall
  change_apk(options)
end
wifi(qualifier) click to toggle source

Returns wifi status and access point name @param qualifier qualifier of device @example

DeviceAPI::ADB.wifi(qualifier)
# File lib/device_api/android/adb.rb, line 288
def self.wifi(qualifier)
  result = shell(qualifier, 'dumpsys wifi | grep mNetworkInfo')

  {:status => result.stdout.match("state:(.*?),")[1].strip, :access_point => result.stdout.match("extra:(.*?),")[1].strip.gsub(/"/,'')}
end