device_api-android 1.0.1 → 1.1.2
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.
- checksums.yaml +4 -4
- data/51-android.rules +2 -0
- data/Gemfile.lock +13 -12
- data/device_api-android.gemspec +2 -2
- data/lib/device_api/android.rb +22 -2
- data/lib/device_api/android/aapt.rb +1 -17
- data/lib/device_api/android/adb.rb +107 -41
- data/lib/device_api/android/device.rb +123 -1
- data/lib/device_api/android/device/kindle.rb +14 -0
- data/lib/device_api/android/plugins/battery.rb +22 -0
- data/lib/device_api/android/plugins/disk.rb +29 -0
- data/lib/device_api/android/plugins/memory.rb +77 -0
- data/lib/device_api/android/signing.rb +2 -2
- data/spec/adb_spec.rb +19 -0
- data/spec/android_device_spec.rb +3 -3
- metadata +7 -6
- data/lib/device_api/android/devices/default.rb +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d056fdaa82d61147897272f7a3df98afd5f8e4af
|
4
|
+
data.tar.gz: ea866645ded8c453e60ac3baec01ee929d983c2e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 856ed8986cc089f9acc2098036a7e1deb95c93f86926f93bdbc2edd22f7cd5f5e4d7e255728049ee2d6321cde1910f54f810f1e3b5cdadba494385b86f9e40aa
|
7
|
+
data.tar.gz: 8b4a040ad4a5a01d652a7b1967ed3e1921726c5dcc1a6f916d76211616c465a9961607148e782f886444c245ac336127bf503c05b76684aa1d7ef1c2f1213caa
|
data/51-android.rules
CHANGED
@@ -50,6 +50,8 @@ SUBSYSTEM=="usb", ATTR{idVendor}=="1949", ATTR{idProduct}=="000b", MODE="0666",
|
|
50
50
|
SUBSYSTEM=="usb", ATTR{idVendor}=="1949", ATTR{idProduct}=="000c", MODE="0666", OWNER="hive"
|
51
51
|
# Kindle Fire (Pink Case)
|
52
52
|
SUBSYSTEM=="usb", ATTR{idVendor}=="1949", ATTR{idProduct}=="00f2", MODE="0666", OWNER="hive"
|
53
|
+
# Kindle Fire HDX 8.9 (3rd Generation) OS 4.5.5
|
54
|
+
SUBSYSTEM=="usb", ATTR{idVendor}=="1949", ATTR{idProduct}=="000d", mode="0666", OWNER="hive"
|
53
55
|
# Sony Ericsson ST25i
|
54
56
|
SUBSYSTEM=="usb", ATTR{idVendor}=="0fce", ATTR{idProduct}=="5171", MODE="0666", OWNER="hive"
|
55
57
|
# Galaxy S2/S3
|
data/Gemfile.lock
CHANGED
@@ -1,20 +1,21 @@
|
|
1
1
|
GEM
|
2
2
|
remote: https://rubygems.org/
|
3
3
|
specs:
|
4
|
-
device_api (1.0.
|
4
|
+
device_api (1.0.1)
|
5
5
|
diff-lcs (1.2.5)
|
6
|
-
rspec (3.
|
7
|
-
rspec-core (~> 3.
|
8
|
-
rspec-expectations (~> 3.
|
9
|
-
rspec-mocks (~> 3.
|
10
|
-
rspec-core (3.
|
11
|
-
rspec-support (~> 3.
|
12
|
-
rspec-expectations (3.0
|
6
|
+
rspec (3.3.0)
|
7
|
+
rspec-core (~> 3.3.0)
|
8
|
+
rspec-expectations (~> 3.3.0)
|
9
|
+
rspec-mocks (~> 3.3.0)
|
10
|
+
rspec-core (3.3.1)
|
11
|
+
rspec-support (~> 3.3.0)
|
12
|
+
rspec-expectations (3.3.0)
|
13
13
|
diff-lcs (>= 1.2.0, < 2.0)
|
14
|
-
rspec-support (~> 3.
|
15
|
-
rspec-mocks (3.
|
16
|
-
|
17
|
-
|
14
|
+
rspec-support (~> 3.3.0)
|
15
|
+
rspec-mocks (3.3.1)
|
16
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
17
|
+
rspec-support (~> 3.3.0)
|
18
|
+
rspec-support (3.3.0)
|
18
19
|
|
19
20
|
PLATFORMS
|
20
21
|
ruby
|
data/device_api-android.gemspec
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'device_api-android'
|
3
|
-
s.version = '1.
|
3
|
+
s.version = '1.1.2'
|
4
4
|
s.date = Time.now.strftime("%Y-%m-%d")
|
5
5
|
s.summary = 'Android Device Management API'
|
6
6
|
s.description = 'Android implementation of DeviceAPI'
|
7
|
-
s.authors = ['
|
7
|
+
s.authors = ['David Buckhurst','Jitesh Gosai', 'Jon Wilson']
|
8
8
|
s.email = 'david.buckhurst@bbc.co.uk'
|
9
9
|
s.files = `git ls-files`.split "\n"
|
10
10
|
s.homepage = 'https://github.com/bbc/device_api-android'
|
data/lib/device_api/android.rb
CHANGED
@@ -3,13 +3,21 @@ require 'device_api/android/adb'
|
|
3
3
|
require 'device_api/android/device'
|
4
4
|
require 'device_api/android/signing'
|
5
5
|
|
6
|
+
# Load plugins
|
7
|
+
require 'device_api/android/plugins/memory'
|
8
|
+
require 'device_api/android/plugins/battery'
|
9
|
+
require 'device_api/android/plugins/disk'
|
10
|
+
|
11
|
+
# Load additional device types
|
12
|
+
require 'device_api/android/device/kindle'
|
13
|
+
|
6
14
|
module DeviceAPI
|
7
15
|
module Android
|
8
16
|
# Returns array of connected android devices
|
9
17
|
def self.devices
|
10
18
|
ADB.devices.map do |d|
|
11
19
|
if d.keys.first && !d.keys.first.include?('?')
|
12
|
-
DeviceAPI::Android::Device.
|
20
|
+
DeviceAPI::Android::Device.create( self.get_device_type(d.keys.first), { serial: d.keys.first, state: d.values.first } )
|
13
21
|
end
|
14
22
|
end
|
15
23
|
end
|
@@ -20,7 +28,19 @@ module DeviceAPI
|
|
20
28
|
raise DeviceAPI::BadSerialString.new("serial was '#{serial.nil? ? 'nil' : serial}'")
|
21
29
|
end
|
22
30
|
state = ADB.get_state(serial)
|
23
|
-
DeviceAPI::Android::Device.
|
31
|
+
DeviceAPI::Android::Device.create( self.get_device_type(serial), { serial: serial, state: state })
|
32
|
+
end
|
33
|
+
|
34
|
+
# Return the device type used in determining which Device Object to create
|
35
|
+
def self.get_device_type(serial)
|
36
|
+
return :default if Device.new(serial: serial).manufacturer.nil?
|
37
|
+
case Device.new(serial: serial).manufacturer.downcase
|
38
|
+
when 'amazon'
|
39
|
+
type = :kindle
|
40
|
+
else
|
41
|
+
type = :default
|
42
|
+
end
|
43
|
+
type
|
24
44
|
end
|
25
45
|
end
|
26
46
|
|
@@ -26,23 +26,7 @@ module DeviceAPI
|
|
26
26
|
|
27
27
|
fail result.stderr if result.exit != 0
|
28
28
|
|
29
|
-
|
30
|
-
results = []
|
31
|
-
lines.each do |l|
|
32
|
-
if /(.*): (.*)/.match(l)
|
33
|
-
# results.push(Regexp.last_match[1].strip => Regexp.last_match[2].strip)
|
34
|
-
values = {}
|
35
|
-
|
36
|
-
Regexp.last_match[2].strip.split(' ').each do |item| # split on an spaces
|
37
|
-
item = item.to_s.tr('\'', '') # trim off any excess single quotes
|
38
|
-
values[item.split('=')[0]] = item.split('=')[1] # split on the = and create a new hash
|
39
|
-
end
|
40
|
-
|
41
|
-
results << {Regexp.last_match[1].strip => values} # append the result tp new_result
|
42
|
-
|
43
|
-
end
|
44
|
-
end
|
45
|
-
results
|
29
|
+
result.stdout.scan(/(.*): (.*)/).map { |a,b| { a => Hash[b.split(' ').map { |c| c.tr('\'','').split('=') }] } }
|
46
30
|
end
|
47
31
|
|
48
32
|
end
|
@@ -18,17 +18,7 @@ module DeviceAPI
|
|
18
18
|
result = execute_with_timeout_and_retry('adb devices')
|
19
19
|
|
20
20
|
raise ADBCommandError.new(result.stderr) if result.exit != 0
|
21
|
-
|
22
|
-
lines = result.stdout.split("\n")
|
23
|
-
results = []
|
24
|
-
|
25
|
-
lines.shift # Drop the message line
|
26
|
-
lines.each do |l|
|
27
|
-
if /(.*)\t(.*)/.match(l)
|
28
|
-
results.push(Regexp.last_match[1].strip => Regexp.last_match[2].strip)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
results
|
21
|
+
result.stdout.scan(/(.*)\t(.*)/).map { |a,b| {a => b}}
|
32
22
|
end
|
33
23
|
|
34
24
|
# Retrieve device state for a single device
|
@@ -54,13 +44,7 @@ module DeviceAPI
|
|
54
44
|
|
55
45
|
lines = result.stdout.split("\n")
|
56
46
|
|
57
|
-
|
58
|
-
lines.each do |l|
|
59
|
-
if /\[(.*)\]:\s+\[(.*)\]/.match(l)
|
60
|
-
props[Regexp.last_match[1]] = Regexp.last_match[2]
|
61
|
-
end
|
62
|
-
end
|
63
|
-
props
|
47
|
+
process_dumpsys('\[(.*)\]:\s+\[(.*)\]', lines)
|
64
48
|
end
|
65
49
|
|
66
50
|
# Get the 'input' information from dumpsys
|
@@ -68,14 +52,7 @@ module DeviceAPI
|
|
68
52
|
# @return (Hash) hash containing input information from dumpsys
|
69
53
|
def self.getdumpsys(serial)
|
70
54
|
lines = dumpsys(serial, 'input')
|
71
|
-
|
72
|
-
props = {}
|
73
|
-
lines.each do |l|
|
74
|
-
if /(.*):\s+(.*)/.match(l)
|
75
|
-
props[Regexp.last_match[1]] = Regexp.last_match[2]
|
76
|
-
end
|
77
|
-
end
|
78
|
-
props
|
55
|
+
process_dumpsys('(.*):\s+(.*)', lines)
|
79
56
|
end
|
80
57
|
|
81
58
|
# Get the 'iphonesubinfo' from dumpsys
|
@@ -83,16 +60,52 @@ module DeviceAPI
|
|
83
60
|
# @return (Hash) hash containing iphonesubinfo information from dumpsys
|
84
61
|
def self.getphoneinfo(serial)
|
85
62
|
lines = dumpsys(serial, 'iphonesubinfo')
|
63
|
+
process_dumpsys('(.*) =\s+(.*)', lines)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Get the 'battery' information from dumpsys
|
67
|
+
# @param [String] serial serial number of device
|
68
|
+
# @return [Hash] hash containing battery information from dumpsys
|
69
|
+
def self.get_battery_info(serial)
|
70
|
+
lines = dumpsys(serial, 'battery')
|
71
|
+
process_dumpsys('(.*):\s+(.*)', lines)
|
72
|
+
end
|
86
73
|
|
74
|
+
# Processes the results from dumpsys to format them into a hash
|
75
|
+
# @param [String] regex_string regex string used to separate the results from the keys
|
76
|
+
# @param [Array] data data returned from dumpsys
|
77
|
+
# @return [Hash] hash containing the keys and values as distinguished by the supplied regex
|
78
|
+
def self.process_dumpsys(regex_string, data)
|
87
79
|
props = {}
|
88
|
-
|
89
|
-
|
80
|
+
regex = Regexp.new(regex_string)
|
81
|
+
data.each do |line|
|
82
|
+
if regex.match(line)
|
90
83
|
props[Regexp.last_match[1]] = Regexp.last_match[2]
|
91
84
|
end
|
92
85
|
end
|
86
|
+
|
93
87
|
props
|
94
88
|
end
|
95
89
|
|
90
|
+
# Get the 'power' information from dumpsys
|
91
|
+
# @param [String] serial serial number of device
|
92
|
+
# @return [Hash] hash containing power information from dumpsys
|
93
|
+
def self.getpowerinfo(serial)
|
94
|
+
lines = dumpsys(serial, 'power')
|
95
|
+
process_dumpsys('(.*)=(.*)', lines)
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.get_device_dpi(serial)
|
99
|
+
lines = dumpsys(serial, 'window')
|
100
|
+
dpi = nil
|
101
|
+
lines.each do |line|
|
102
|
+
if /sw(\d*)dp/.match(line)
|
103
|
+
dpi = Regexp.last_match[1]
|
104
|
+
end
|
105
|
+
end
|
106
|
+
dpi
|
107
|
+
end
|
108
|
+
|
96
109
|
# Returns the 'dumpsys' information from the specified device
|
97
110
|
# @param serial serial number of device
|
98
111
|
# @return (Array) array of results from adb shell dumpsys
|
@@ -108,18 +121,8 @@ module DeviceAPI
|
|
108
121
|
# @option options [String] :serial serial number of device
|
109
122
|
# @return (String) return result from adb install command
|
110
123
|
def self.install_apk(options = {})
|
111
|
-
|
112
|
-
|
113
|
-
result = execute("adb -s #{serial} install #{apk}")
|
114
|
-
|
115
|
-
raise ADBCommandError.new(result.stderr) if result.exit != 0
|
116
|
-
|
117
|
-
lines = result.stdout.split("\n").map { |line| line.strip }
|
118
|
-
# lines.each do |line|
|
119
|
-
# res=:success if line=='Success'
|
120
|
-
# end
|
121
|
-
|
122
|
-
lines.last
|
124
|
+
options[:action] = :install
|
125
|
+
change_apk(options)
|
123
126
|
end
|
124
127
|
|
125
128
|
# Uninstalls a specified package from a specified device
|
@@ -128,9 +131,27 @@ module DeviceAPI
|
|
128
131
|
# @option options [String] :serial serial number of device
|
129
132
|
# @return (String) return result from adb uninstall command
|
130
133
|
def self.uninstall_apk(options = {})
|
134
|
+
options[:action] = :uninstall
|
135
|
+
change_apk(options)
|
136
|
+
end
|
137
|
+
|
138
|
+
def self.change_apk(options = {})
|
131
139
|
package_name = options[:package_name]
|
140
|
+
apk = options[:apk]
|
132
141
|
serial = options[:serial]
|
133
|
-
|
142
|
+
action = options[:action]
|
143
|
+
|
144
|
+
case action
|
145
|
+
when :install
|
146
|
+
command = "adb -s #{serial} install #{apk}"
|
147
|
+
when :uninstall
|
148
|
+
command = "adb -s #{serial} uninstall #{package_name}"
|
149
|
+
else
|
150
|
+
raise ADBCommandError.new('No action specified')
|
151
|
+
end
|
152
|
+
|
153
|
+
result = execute(command)
|
154
|
+
|
134
155
|
raise ADBCommandError.new(result.stderr) if result.exit != 0
|
135
156
|
|
136
157
|
lines = result.stdout.split("\n").map { |line| line.strip }
|
@@ -203,6 +224,51 @@ module DeviceAPI
|
|
203
224
|
execute(cmd)
|
204
225
|
end
|
205
226
|
|
227
|
+
# Returns wifi status and access point name
|
228
|
+
# @param serial serial number of device
|
229
|
+
# @example
|
230
|
+
# DeviceAPI::ADB.wifi(serial)
|
231
|
+
def self.wifi(serial)
|
232
|
+
result = execute("adb -s #{serial} shell dumpsys wifi | grep mNetworkInfo")
|
233
|
+
if result.exit != 0
|
234
|
+
raise ADBCommandError.new(result.stderr)
|
235
|
+
else
|
236
|
+
result = {:status => result.stdout.match("state:(.*?),")[1].strip, :access_point => result.stdout.match("extra:(.*?),")[1].strip.gsub(/"/,'')}
|
237
|
+
end
|
238
|
+
result
|
239
|
+
end
|
240
|
+
|
241
|
+
# Sends a key event to the specified device
|
242
|
+
# @param [String] serial serial number of device
|
243
|
+
# @param [String] keyevent keyevent to send to the device
|
244
|
+
def self.keyevent(serial, keyevent)
|
245
|
+
result = execute("adb -s #{serial} shell input keyevent #{keyevent}")
|
246
|
+
raise ADBCommandError.new(result.stderr) if result.exit != 0
|
247
|
+
end
|
248
|
+
|
249
|
+
# Sends a swipe command to the specified device
|
250
|
+
# @param [String] serial serial number of the device
|
251
|
+
# @param [Hash] coords hash of coordinates to swipe from / to
|
252
|
+
# @option coords [String] :x_from (0) Coordinate to start from on the X axis
|
253
|
+
# @option coords [String] :x_to (0) Coordinate to end on on the X axis
|
254
|
+
# @option coords [String] :y_from (0) Coordinate to start from on the Y axis
|
255
|
+
# @option coords [String] :y_to (0) Coordinate to end on on the Y axis
|
256
|
+
def self.swipe(serial, coords = {x_from: 0, x_to: 0, y_from: 0, y_to: 0 })
|
257
|
+
execute("adb -s #{serial} shell input swipe #{coords[:x_from]} #{coords[:x_to]} #{coords[:y_from]} #{coords[:y_to]}")
|
258
|
+
raise ADBCommandError.new(result.stderr) if result.exit != 0
|
259
|
+
end
|
260
|
+
|
261
|
+
# Starts intent using adb
|
262
|
+
# Returns stdout
|
263
|
+
# @param serial serial number of device
|
264
|
+
# @param command -option activity
|
265
|
+
# @example
|
266
|
+
# DeviceAPI::ADB.am(serial, "-a android.intent.action.MAIN -n com.android.settings/.wifi.WifiSettings")
|
267
|
+
def self.am(serial, command)
|
268
|
+
result = execute("adb -s #{serial} shell am start #{command}")
|
269
|
+
raise ADBCommandError.new(result.stderr) if result.exit != 0
|
270
|
+
return result.stdout
|
271
|
+
end
|
206
272
|
end
|
207
273
|
|
208
274
|
# ADB Error class
|
@@ -9,6 +9,21 @@ module DeviceAPI
|
|
9
9
|
module Android
|
10
10
|
# Device class used for containing the accessors of the physical device information
|
11
11
|
class Device < DeviceAPI::Device
|
12
|
+
|
13
|
+
@@subclasses; @@subclasses = {}
|
14
|
+
|
15
|
+
# Called by any inheritors to register themselves with the parent class
|
16
|
+
def self.inherited(klass)
|
17
|
+
key = /::([^:]+)$/.match(klass.to_s.downcase)[1].to_sym
|
18
|
+
@@subclasses[key] = klass
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns an object of the specified type, if it exists. Defaults to returning self
|
22
|
+
def self.create(type, options = {} )
|
23
|
+
return @@subclasses[type.to_sym].new(options) if @@subclasses[type.to_sym]
|
24
|
+
return self.new(options)
|
25
|
+
end
|
26
|
+
|
12
27
|
def initialize(options = {})
|
13
28
|
@serial = options[:serial]
|
14
29
|
@state = options[:state]
|
@@ -58,13 +73,25 @@ module DeviceAPI
|
|
58
73
|
get_prop('ro.build.version.release')
|
59
74
|
end
|
60
75
|
|
76
|
+
# Return the battery level
|
77
|
+
# @return (String) device battery level
|
78
|
+
def battery_level
|
79
|
+
get_battery_info['level']
|
80
|
+
end
|
81
|
+
|
82
|
+
# Is the device currently being powered?
|
83
|
+
# @return (Boolean) true if it is being powered in some way, false if it is unpowered
|
84
|
+
def powered?
|
85
|
+
!get_battery_info.select { |keys| keys.include?('powered')}.select { |_,v| v == 'true' }.empty?
|
86
|
+
end
|
87
|
+
|
61
88
|
# Return the device orientation
|
62
89
|
# @return (String) current device orientation
|
63
90
|
def orientation
|
64
91
|
res = get_dumpsys('SurfaceOrientation')
|
65
92
|
|
66
93
|
case res
|
67
|
-
when '0'
|
94
|
+
when '0','2'
|
68
95
|
:portrait
|
69
96
|
when '1', '3'
|
70
97
|
:landscape
|
@@ -141,8 +168,94 @@ module DeviceAPI
|
|
141
168
|
get_phoneinfo['Device ID']
|
142
169
|
end
|
143
170
|
|
171
|
+
# Get the memory information for the current device
|
172
|
+
# @return [DeviceAPI::Android::Plugins::Memory] the memory plugin containing relevant information
|
173
|
+
def memory
|
174
|
+
get_memory_info
|
175
|
+
end
|
176
|
+
|
177
|
+
def battery
|
178
|
+
get_battery_info
|
179
|
+
end
|
180
|
+
|
181
|
+
# Check if the devices screen is currently turned on
|
182
|
+
# @return [Boolean] true if the screen is on, otherwise false
|
183
|
+
def screen_on?
|
184
|
+
return true if get_powerinfo['mScreenOn'].to_s.downcase == 'true'
|
185
|
+
false
|
186
|
+
end
|
187
|
+
|
188
|
+
# Unlock the device by sending a wakeup command
|
189
|
+
def unlock
|
190
|
+
ADB.keyevent(serial, '26') unless screen_on?
|
191
|
+
end
|
192
|
+
|
193
|
+
# Return the DPI of the attached device
|
194
|
+
# @return [String] DPI of attached device
|
195
|
+
def dpi
|
196
|
+
get_dpi(serial)
|
197
|
+
end
|
198
|
+
|
199
|
+
# Return the device type based on the DPI
|
200
|
+
# @return [Symbol] :tablet or :mobile based upon the devices DPI
|
201
|
+
def type
|
202
|
+
if get_dpi.to_i > 533
|
203
|
+
:tablet
|
204
|
+
else
|
205
|
+
:mobile
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
# Returns wifi status and access point name
|
210
|
+
# @return [Hash] :status and :access_point
|
211
|
+
def wifi_status
|
212
|
+
ADB.wifi(serial)
|
213
|
+
end
|
214
|
+
|
215
|
+
def battery_info
|
216
|
+
ADB.get_battery_info(serial)
|
217
|
+
end
|
218
|
+
|
219
|
+
# @param [String] command to start the intent
|
220
|
+
# Return the stdout of executed intent
|
221
|
+
# @return [String] stdout
|
222
|
+
def start_intent(command)
|
223
|
+
ADB.am(serial,command)
|
224
|
+
end
|
225
|
+
|
226
|
+
#Reboots the device
|
227
|
+
def reboot
|
228
|
+
ADB.reboot(serial)
|
229
|
+
end
|
230
|
+
|
231
|
+
# Returns disk status
|
232
|
+
# @return [Hash] containing disk statistics
|
233
|
+
def diskstat
|
234
|
+
get_disk_info
|
235
|
+
end
|
236
|
+
|
237
|
+
# Returns the device uptime
|
238
|
+
def uptime
|
239
|
+
ADB.get_uptime(serial)
|
240
|
+
end
|
241
|
+
|
144
242
|
private
|
145
243
|
|
244
|
+
def get_disk_info
|
245
|
+
@diskstat = DeviceAPI::Android::Plugin::Disk.new(serial: serial) unless @diskstat
|
246
|
+
@diskstat.process_stats
|
247
|
+
end
|
248
|
+
|
249
|
+
def get_battery_info
|
250
|
+
@battery = DeviceAPI::Android::Plugin::Battery.new(serial: serial) unless @battery
|
251
|
+
@battery
|
252
|
+
end
|
253
|
+
|
254
|
+
def get_memory_info
|
255
|
+
@memory = DeviceAPI::Android::Plugin::Memory.new(serial: serial) unless @memory
|
256
|
+
@memory
|
257
|
+
end
|
258
|
+
|
146
259
|
def get_app_props(key)
|
147
260
|
unless @app_props
|
148
261
|
@app_props = AAPT.get_app_props(@apk)
|
@@ -162,6 +275,11 @@ module DeviceAPI
|
|
162
275
|
@props[key]
|
163
276
|
end
|
164
277
|
|
278
|
+
def get_powerinfo
|
279
|
+
ADB.getpowerinfo(serial)
|
280
|
+
end
|
281
|
+
|
282
|
+
|
165
283
|
def get_phoneinfo
|
166
284
|
ADB.getphoneinfo(serial)
|
167
285
|
end
|
@@ -173,6 +291,10 @@ module DeviceAPI
|
|
173
291
|
def uninstall_apk(package_name)
|
174
292
|
ADB.uninstall_apk(package_name: package_name, serial: serial)
|
175
293
|
end
|
294
|
+
|
295
|
+
def get_dpi
|
296
|
+
ADB.get_device_dpi(serial)
|
297
|
+
end
|
176
298
|
end
|
177
299
|
end
|
178
300
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module DeviceAPI
|
2
|
+
module Android
|
3
|
+
# Kindle specific device class
|
4
|
+
class Kindle < Device
|
5
|
+
# On non-Kindle devices, if a device is locked without a password (i.e. 'Swipe to unlock'), then
|
6
|
+
# you can unlock that device by broadcasting a 'WakeUp' intent. On Kindle devices, this does not
|
7
|
+
# work due to Amazons implementation of the Keyguard.
|
8
|
+
def unlock
|
9
|
+
ADB.keyevent(serial, '26') unless screen_on?
|
10
|
+
ADB.swipe(serial, { x_from: 900, x_to: 300, y_from: 100, y_to: 100 } )
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module DeviceAPI
|
2
|
+
module Android
|
3
|
+
module Plugin
|
4
|
+
class Battery
|
5
|
+
attr_reader :current_temp, :max_temp, :max_current, :voltage, :level, :health, :status
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
serial = options[:serial]
|
9
|
+
props = ADB.get_battery_info(serial)
|
10
|
+
@current_temp = props["temperature"]
|
11
|
+
@max_temp = props["mBatteryMaxTemp"]
|
12
|
+
@max_current = props["mBatteryMaxCurrent"]
|
13
|
+
@voltage = props["voltage"]
|
14
|
+
@level = props["level"]
|
15
|
+
@health = props["health"]
|
16
|
+
@status = props["status"]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module DeviceAPI
|
2
|
+
module Android
|
3
|
+
module Plugin
|
4
|
+
class Disk
|
5
|
+
|
6
|
+
attr_reader :serial
|
7
|
+
def initialize(options = {})
|
8
|
+
@serial = options[:serial]
|
9
|
+
end
|
10
|
+
|
11
|
+
def process_stats(options = {})
|
12
|
+
disk_info = {}
|
13
|
+
stats = options[:data] || ADB.dumpsys(@serial, 'diskstats')
|
14
|
+
stats.each do |stat|
|
15
|
+
if /(.*)-.*:\s(.*)\s\/\s([0-9]*[A-Z])\s[a-z]*\s=\s([0-9]*%)/.match(stat)
|
16
|
+
disk_info["#{Regexp.last_match[1].downcase}_total"] = Regexp.last_match[3]
|
17
|
+
disk_info["#{Regexp.last_match[1].downcase}_free"] = Regexp.last_match[4]
|
18
|
+
disk_info["#{Regexp.last_match[1].downcase}_used"] = Regexp.last_match[2]
|
19
|
+
elsif /(.*):\s(\S*)/.match(stat)
|
20
|
+
disk_info[Regexp.last_match[1].downcase] = Regexp.last_match[2]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
disk_info
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module DeviceAPI
|
2
|
+
module Android
|
3
|
+
# Plugins contain extra information about the attached device(s)
|
4
|
+
module Plugin
|
5
|
+
# Class used to provide information about process memory usage
|
6
|
+
# and device memory usage
|
7
|
+
class Memory
|
8
|
+
|
9
|
+
# Class used for holding process information
|
10
|
+
class MemInfo
|
11
|
+
attr_reader :process, :memory, :pid
|
12
|
+
def initialize(options = {})
|
13
|
+
@process = options[:process]
|
14
|
+
@memory = options[:memory]
|
15
|
+
@pid = options[:pid]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Class used for storing process information
|
20
|
+
class RAM
|
21
|
+
attr_accessor :total, :free, :used, :lost, :tuning
|
22
|
+
def initialize(options = {})
|
23
|
+
@total = options[:total]
|
24
|
+
@free = options[:free]
|
25
|
+
@used = options[:used]
|
26
|
+
@lost = options[:lost]
|
27
|
+
@tuning = options[:tuning]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
attr_accessor :processes, :mem_info
|
32
|
+
|
33
|
+
def initialize(options = {})
|
34
|
+
@serial = options[:serial]
|
35
|
+
info = options[:data] || ADB.dumpsys(@serial, 'meminfo')
|
36
|
+
process_data(info)
|
37
|
+
end
|
38
|
+
|
39
|
+
def process_data(memory_info)
|
40
|
+
groups = memory_info.chunk { |a| a == '' }.reject { |a,_| a }.map { |_,b| b }
|
41
|
+
|
42
|
+
raise 'A different ADB result has been received' unless groups[1].first == 'Total PSS by process:'
|
43
|
+
@processes = []
|
44
|
+
process_total_pss_by_process(groups[1])
|
45
|
+
process_ram_info(groups[4])
|
46
|
+
end
|
47
|
+
|
48
|
+
def update
|
49
|
+
meminfo = ADB.dumpsys(@serial, 'meminfo')
|
50
|
+
process_data(meminfo)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Processes memory used by each running process
|
54
|
+
def process_total_pss_by_process(data)
|
55
|
+
data.each do |l|
|
56
|
+
if /(.*):\s+(.*)\s+\(.*pid\s+(\S*).*\)/.match(l)
|
57
|
+
@processes << MemInfo.new(process: Regexp.last_match[2], memory: Regexp.last_match[1], pid: Regexp.last_match[3] )
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Processes memory used by the device
|
63
|
+
def process_ram_info(data)
|
64
|
+
ram_info = {}
|
65
|
+
data.each do |l|
|
66
|
+
if /Tuning:\s+(.*)/.match(l)
|
67
|
+
ram_info['tuning'] = Regexp.last_match[1]
|
68
|
+
elsif /(.*):\s(-?[0-9]*\s\S*)/.match(l)
|
69
|
+
ram_info[Regexp.last_match[1].downcase] = Regexp.last_match[2]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
@mem_info = RAM.new(total: ram_info['total ram'], free: ram_info['free ram'], used: ram_info['used ram'], lost: ram_info['lost'], tuning: ram_info['tuning'])
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -54,7 +54,7 @@ module DeviceAPI
|
|
54
54
|
# @param [String] apk_path full path to apk to check
|
55
55
|
# @return returns false if the apk is unsigned, true if it is signed
|
56
56
|
def self.is_apk_signed?(apk_path)
|
57
|
-
result = execute("aapt list #{apk_path} | grep '^META-INF
|
57
|
+
result = execute("aapt list #{apk_path} | grep '^META-INF\/.*'")
|
58
58
|
return false if result.stdout.empty?
|
59
59
|
true
|
60
60
|
end
|
@@ -63,7 +63,7 @@ module DeviceAPI
|
|
63
63
|
# @param [String] apk_path full path to the apk
|
64
64
|
# @return [Boolean, Exception] returns true if the apk is successfully unsigned, otherwise an exception is raised
|
65
65
|
def self.unsign_apk(apk_path)
|
66
|
-
file_list = execute("aapt list #{apk_path} | grep '^META-INF
|
66
|
+
file_list = execute("aapt list #{apk_path} | grep '^META-INF\/.*'")
|
67
67
|
result = execute("aapt remove #{apk_path} #{file_list.stdout.split(/\s+/).join(' ')}")
|
68
68
|
raise SigningCommandError.new(result.stderr) if result.exit != 0
|
69
69
|
true
|
data/spec/adb_spec.rb
CHANGED
@@ -135,4 +135,23 @@ _______________________________________________________
|
|
135
135
|
end
|
136
136
|
end
|
137
137
|
|
138
|
+
describe ".wifi" do
|
139
|
+
it "returns wifi info" do
|
140
|
+
out= <<_______________________________________________________
|
141
|
+
mNetworkInfo [type: WIFI[], state: CONNECTED/CONNECTED, reason: (unspecified), extra: "TVMP-DevNet", roaming: false, failover: false, isAvailable: true, isConnectedToProvisioningNetwork: false]
|
142
|
+
_______________________________________________________
|
143
|
+
allow(Open3).to receive(:capture3) { [out, '', $STATUS_ZERO] }
|
144
|
+
expect( DeviceAPI::Android::ADB.wifi('12345').class).to eq(Hash)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
describe ".am" do
|
149
|
+
it "returns the stdout" do
|
150
|
+
out= <<_______________________________________________________
|
151
|
+
Starting: Intent { act=android.intent.action.MAIN cmp=com.android.settings/.wifi.WifiSettings }
|
152
|
+
_______________________________________________________
|
153
|
+
allow(Open3).to receive(:capture3) { [out, '', $STATUS_ZERO] }
|
154
|
+
expect( DeviceAPI::Android::ADB.am('03157df373208426' ,'12345').class).to eq(String)
|
155
|
+
end
|
156
|
+
end
|
138
157
|
end
|
data/spec/android_device_spec.rb
CHANGED
@@ -7,7 +7,7 @@ describe DeviceAPI::Android do
|
|
7
7
|
|
8
8
|
it 'Returns an empty array when no devices are connected' do
|
9
9
|
out = <<_______________________________________________________
|
10
|
-
|
10
|
+
List of devices attached
|
11
11
|
|
12
12
|
_______________________________________________________
|
13
13
|
allow(Open3).to receive(:capture3) { [out, '', $STATUS_ZERO] }
|
@@ -16,8 +16,8 @@ _______________________________________________________
|
|
16
16
|
|
17
17
|
it "returns an array with a single item when there's one device attached" do
|
18
18
|
out = <<_______________________________________________________
|
19
|
-
|
20
|
-
|
19
|
+
List of devices attached
|
20
|
+
SH34RW905290 device
|
21
21
|
|
22
22
|
_______________________________________________________
|
23
23
|
allow(Open3).to receive(:capture3) { [out, '', $STATUS_ZERO] }
|
metadata
CHANGED
@@ -1,17 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: device_api-android
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
- BBC
|
8
7
|
- David Buckhurst
|
9
8
|
- Jitesh Gosai
|
10
9
|
- Jon Wilson
|
11
10
|
autorequire:
|
12
11
|
bindir: bin
|
13
12
|
cert_chain: []
|
14
|
-
date: 2015-
|
13
|
+
date: 2015-10-06 00:00:00.000000000 Z
|
15
14
|
dependencies:
|
16
15
|
- !ruby/object:Gem::Dependency
|
17
16
|
name: device_api
|
@@ -64,7 +63,10 @@ files:
|
|
64
63
|
- lib/device_api/android/aapt.rb
|
65
64
|
- lib/device_api/android/adb.rb
|
66
65
|
- lib/device_api/android/device.rb
|
67
|
-
- lib/device_api/android/
|
66
|
+
- lib/device_api/android/device/kindle.rb
|
67
|
+
- lib/device_api/android/plugins/battery.rb
|
68
|
+
- lib/device_api/android/plugins/disk.rb
|
69
|
+
- lib/device_api/android/plugins/memory.rb
|
68
70
|
- lib/device_api/android/signing.rb
|
69
71
|
- spec/adb_spec.rb
|
70
72
|
- spec/android_device_spec.rb
|
@@ -90,9 +92,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
90
92
|
version: '0'
|
91
93
|
requirements: []
|
92
94
|
rubyforge_project:
|
93
|
-
rubygems_version: 2.4.
|
95
|
+
rubygems_version: 2.4.8
|
94
96
|
signing_key:
|
95
97
|
specification_version: 4
|
96
98
|
summary: Android Device Management API
|
97
99
|
test_files: []
|
98
|
-
has_rdoc:
|
File without changes
|