Class: DeviceAPI::Android::ADB

Inherits:
Execution
  • Object
show all
Defined in:
lib/device_api/android/adb.rb

Overview

Namespace for all methods encapsulating adb calls

Class Method Summary collapse

Class Method Details

.am(qualifier, command) ⇒ Object

Starts intent using adb Returns stdout DeviceAPI::ADB.am(qualifier, “start -a android.intent.action.MAIN -n com.android.settings/.wifi.WifiSettings”)



321
322
323
# File 'lib/device_api/android/adb.rb', line 321

def self.am(qualifier, command)
  shell(qualifier, "am #{command}").stdout
end

.block_package(qualifier, package) ⇒ Object

Blocks a package, used on Android versions less than KitKat Returns boolean



337
338
339
340
# File 'lib/device_api/android/adb.rb', line 337

def self.block_package(qualifier, package)
  result = pm(qualifier, "block #{package}")
  result.include?('true')
end

.change_apk(options = {}) ⇒ Object

Raises:



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# 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) ⇒ Object



351
352
353
354
355
# File 'lib/device_api/android/adb.rb', line 351

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) ⇒ Object

Connects to remote android device

Examples:

DeviceAPI::ADB.connect(ip_address, port)  


241
242
243
244
245
246
247
248
249
250
251
252
253
# File 'lib/device_api/android/adb.rb', line 241

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

.devicesArray

Returns an array representing connected devices DeviceAPI::ADB.devices #=> { ‘1232132’ => ‘device’ }

Raises:



17
18
19
20
21
22
# 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) ⇒ Object

Disconnects from remote android device

Examples:

DeviceAPI::ADB.disconnect(ip_address, port) 


260
261
262
263
264
265
266
267
268
# File 'lib/device_api/android/adb.rb', line 260

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) ⇒ Array

Returns the ‘dumpsys’ information from the specified device



124
125
126
127
# 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) ⇒ Hash

Get the ‘battery’ information from dumpsys



67
68
69
70
# 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) ⇒ Object



110
111
112
113
114
115
116
117
118
119
# 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) ⇒ Object

Get the network information



78
79
80
81
82
83
84
# 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) ⇒ Object



72
73
74
75
# 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) ⇒ String

Retrieve device state for a single device

Raises:



27
28
29
30
31
32
33
34
35
# File 'lib/device_api/android/adb.rb', line 27

def self.get_state(qualifier)
  result = execute('adb get-state -s #{qualifier}')

  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) ⇒ Float

Returns the uptime of the specified device



176
177
178
179
180
181
182
183
184
185
186
187
# 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) ⇒ Hash

Get the ‘input’ information from dumpsys



51
52
53
54
# File 'lib/device_api/android/adb.rb', line 51

def self.getdumpsys(qualifier)
  lines = dumpsys(qualifier, 'input')
  process_dumpsys('(.*):\s+(.*)', lines)
end

.getphoneinfo(qualifier) ⇒ Hash

Get the ‘iphonesubinfo’ from dumpsys



59
60
61
62
# File 'lib/device_api/android/adb.rb', line 59

def self.getphoneinfo(qualifier)
  lines = dumpsys(qualifier, 'iphonesubinfo')
  process_dumpsys('(.*) =\s+(.*)', lines)
end

.getpowerinfo(qualifier) ⇒ Hash

Get the ‘power’ information from dumpsys



105
106
107
108
# File 'lib/device_api/android/adb.rb', line 105

def self.getpowerinfo(qualifier)
  lines = dumpsys(qualifier, 'power')
  process_dumpsys('(.*)=(.*)', lines)
end

.getprop(qualifier) ⇒ Hash

Get the properties of a specified device



40
41
42
43
44
45
46
# 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) ⇒ Object

Blocks a package on KitKat and above Returns boolean



346
347
348
349
# File 'lib/device_api/android/adb.rb', line 346

def self.hide_package(qualifier, package)
  result = pm(qualifier, "hide #{package}")
  result.include?('true')
end

.install_apk(options = {}) ⇒ String

Installs a specified apk to a specific device

Options Hash (options):

  • :apk (String)

    path to apk to install

  • :qualifier (String)

    qualifier of device



134
135
136
137
# File 'lib/device_api/android/adb.rb', line 134

def self.install_apk(options = {})
  options[:action] = :install
  change_apk(options)
end

.keyevent(qualifier, keyevent) ⇒ Object

Sends a key event to the specified device



283
284
285
# File 'lib/device_api/android/adb.rb', line 283

def self.keyevent(qualifier, keyevent)
  shell(qualifier, "input keyevent #{keyevent}").stdout
end

.monkey(qualifier, args) ⇒ Object

Runs monkey testing

Examples:

DeviceAPI::ADB.monkey( qualifier, :package => 'my.lovely.app' )

Options Hash (args):

  • :events (String) — default: 10000

    number of events to run

  • :package (String)

    name of package to run the tests against

  • :seed (String)

    pass the seed number (optional)

  • :throttle (String)

    throttle value (optional)



206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/device_api/android/adb.rb', line 206

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) ⇒ Object

Package manager commands

Examples:

DeviceAPI::ADB.pm(qualifier, ‘list packages’)



329
330
331
# File 'lib/device_api/android/adb.rb', line 329

def self.pm(qualifier, command)
  shell(qualifier, "pm #{command}").stdout
end

.process_dumpsys(regex_string, data) ⇒ Hash

Processes the results from dumpsys to format them into a hash



90
91
92
93
94
95
96
97
98
99
100
# 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) ⇒ nil

Reboots the specified device

Raises:



192
193
194
195
# File 'lib/device_api/android/adb.rb', line 192

def self.reboot(qualifier)
  result = execute("adb -s #{qualifier} reboot")
  raise ADBCommandError.new(result.stderr) if result.exit != 0
end

.screencap(qualifier, args) ⇒ Object

Take a screenshot from the device

Examples:

DeviceAPI::ADB.screenshot( qualifier, :filename => '/tmp/filename.png' )

Options Hash (args):

  • :filename (String)

    name (with full path) required to save the image



226
227
228
229
230
231
232
233
234
# File 'lib/device_api/android/adb.rb', line 226

def self.screencap( qualifier, args )
  
  filename = args[:filename] or raise "filename not provided (:filename => '/tmp/myfile.png')"
  
  convert_carriage_returns = %q{perl -pe 's/\x0D\x0A/\x0A/g'}
  cmd = "screencap -p | #{convert_carriage_returns} > #{filename}"
  
  shell(qualifier, cmd)
end

.shell(qualifier, command) ⇒ Object

ADB Shell command



290
291
292
293
294
295
296
297
298
299
300
301
302
# File 'lib/device_api/android/adb.rb', line 290

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
  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 }) ⇒ Object

Sends a swipe command to the specified device

Options Hash (coords):

  • :x_from (String) — default: 0

    Coordinate to start from on the X axis

  • :x_to (String) — default: 0

    Coordinate to end on on the X axis

  • :y_from (String) — default: 0

    Coordinate to start from on the Y axis

  • :y_to (String) — default: 0

    Coordinate to end on on the Y axis



311
312
313
# File 'lib/device_api/android/adb.rb', line 311

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 = {}) ⇒ String

Uninstalls a specified package from a specified device

Options Hash (options):

  • :package_name (String)

    package to uninstall

  • :qualifier (String)

    qualifier of device



144
145
146
147
# File 'lib/device_api/android/adb.rb', line 144

def self.uninstall_apk(options = {})
  options[:action] = :uninstall
  change_apk(options)
end

.wifi(qualifier) ⇒ Object

Returns wifi status and access point name

Examples:

DeviceAPI::ADB.wifi(qualifier)


274
275
276
277
278
# File 'lib/device_api/android/adb.rb', line 274

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