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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d7f064ddcac962170d4089858a6a791625388805
4
- data.tar.gz: 819b3797ef5b61c59383682c3758dcfa48ceb00d
3
+ metadata.gz: d056fdaa82d61147897272f7a3df98afd5f8e4af
4
+ data.tar.gz: ea866645ded8c453e60ac3baec01ee929d983c2e
5
5
  SHA512:
6
- metadata.gz: 819d33204b007a4ddfad07262978c0832f980287810d170e23f0034f7b8e06a203699bf98da9538a71d6549121a8de2e5010d29367120e3820ba090a0a923aef
7
- data.tar.gz: b55962d0d3e0511ea0877f4908c7d552916009b8d8ea43101ed16d90a2e656b58c5b67795766a2b4563fc502a850471408f9257ae42e2f8bfe52b7788edcc108
6
+ metadata.gz: 856ed8986cc089f9acc2098036a7e1deb95c93f86926f93bdbc2edd22f7cd5f5e4d7e255728049ee2d6321cde1910f54f810f1e3b5cdadba494385b86f9e40aa
7
+ data.tar.gz: 8b4a040ad4a5a01d652a7b1967ed3e1921726c5dcc1a6f916d76211616c465a9961607148e782f886444c245ac336127bf503c05b76684aa1d7ef1c2f1213caa
@@ -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
@@ -1,20 +1,21 @@
1
1
  GEM
2
2
  remote: https://rubygems.org/
3
3
  specs:
4
- device_api (1.0.0)
4
+ device_api (1.0.1)
5
5
  diff-lcs (1.2.5)
6
- rspec (3.0.0)
7
- rspec-core (~> 3.0.0)
8
- rspec-expectations (~> 3.0.0)
9
- rspec-mocks (~> 3.0.0)
10
- rspec-core (3.0.4)
11
- rspec-support (~> 3.0.0)
12
- rspec-expectations (3.0.4)
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.0.0)
15
- rspec-mocks (3.0.4)
16
- rspec-support (~> 3.0.0)
17
- rspec-support (3.0.4)
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
@@ -1,10 +1,10 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'device_api-android'
3
- s.version = '1.0.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 = ['BBC','David Buckhurst','Jitesh Gosai', 'Jon Wilson']
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'
@@ -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.new(serial: d.keys.first, state: d.values.first)
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.new(serial: serial, state: state)
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
- lines = result.stdout.split("\n")
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
- props = {}
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
- lines.each do |l|
89
- if /(.*) =\s+(.*)/.match(l)
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
- apk = options[:apk]
112
- serial = options[:serial]
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
- result = execute("adb -s #{serial} uninstall #{package_name}")
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.*\.RSA$'")
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.*\.RSA$'")
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
@@ -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
@@ -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
- List of devices attached
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
- List of devices attached
20
- SH34RW905290 device
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.0.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-05-22 00:00:00.000000000 Z
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/devices/default.rb
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.5
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