calabash 1.2.1 → 1.9.9.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (137) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +39 -0
  3. data/LICENSE +204 -21
  4. data/README.md +36 -6
  5. data/VERSIONING.md +16 -0
  6. data/bin/calabash +95 -0
  7. data/lib/calabash.rb +185 -1
  8. data/lib/calabash/android.rb +64 -0
  9. data/lib/calabash/android/adb.rb +277 -0
  10. data/lib/calabash/android/application.rb +110 -0
  11. data/lib/calabash/android/build.rb +12 -0
  12. data/lib/calabash/android/build/application.rb +13 -0
  13. data/lib/calabash/android/build/build_error.rb +11 -0
  14. data/lib/calabash/android/build/builder.rb +119 -0
  15. data/lib/calabash/android/build/java_keystore.rb +177 -0
  16. data/lib/calabash/android/build/resigner.rb +56 -0
  17. data/lib/calabash/android/build/test_server.rb +27 -0
  18. data/lib/calabash/android/console_helpers.rb +44 -0
  19. data/lib/calabash/android/cucumber.rb +3 -0
  20. data/lib/calabash/android/device.rb +965 -0
  21. data/lib/calabash/android/environment.rb +470 -0
  22. data/lib/calabash/android/gestures.rb +369 -0
  23. data/lib/calabash/android/interactions.rb +45 -0
  24. data/lib/calabash/android/lib/.irbrc +55 -0
  25. data/lib/calabash/android/lib/AndroidManifest.xml +51 -0
  26. data/lib/calabash/android/lib/TestServer.apk +0 -0
  27. data/lib/calabash/android/lib/calmd5/arm64-v8a/calmd5 +0 -0
  28. data/lib/calabash/android/lib/calmd5/arm64-v8a/calmd5-pie +0 -0
  29. data/lib/calabash/android/lib/calmd5/armeabi-v7a/calmd5 +0 -0
  30. data/lib/calabash/android/lib/calmd5/armeabi-v7a/calmd5-pie +0 -0
  31. data/lib/calabash/android/lib/calmd5/armeabi/calmd5 +0 -0
  32. data/lib/calabash/android/lib/calmd5/armeabi/calmd5-pie +0 -0
  33. data/lib/calabash/android/lib/calmd5/mips/calmd5 +0 -0
  34. data/lib/calabash/android/lib/calmd5/mips/calmd5-pie +0 -0
  35. data/lib/calabash/android/lib/calmd5/mips64/calmd5 +0 -0
  36. data/lib/calabash/android/lib/calmd5/mips64/calmd5-pie +0 -0
  37. data/lib/calabash/android/lib/calmd5/x86/calmd5 +0 -0
  38. data/lib/calabash/android/lib/calmd5/x86/calmd5-pie +0 -0
  39. data/lib/calabash/android/lib/calmd5/x86_64/calmd5 +0 -0
  40. data/lib/calabash/android/lib/calmd5/x86_64/calmd5-pie +0 -0
  41. data/lib/calabash/android/lib/screenshot_taker.jar +0 -0
  42. data/lib/calabash/android/life_cycle.rb +37 -0
  43. data/lib/calabash/android/orientation.rb +30 -0
  44. data/lib/calabash/android/physical_buttons.rb +39 -0
  45. data/lib/calabash/android/screenshot.rb +9 -0
  46. data/lib/calabash/android/scroll.rb +5 -0
  47. data/lib/calabash/android/server.rb +10 -0
  48. data/lib/calabash/android/text.rb +54 -0
  49. data/lib/calabash/application.rb +74 -0
  50. data/lib/calabash/cli.rb +12 -0
  51. data/lib/calabash/cli/build.rb +33 -0
  52. data/lib/calabash/cli/console.rb +90 -0
  53. data/lib/calabash/cli/generate.rb +110 -0
  54. data/lib/calabash/cli/helpers.rb +130 -0
  55. data/lib/calabash/cli/resign.rb +33 -0
  56. data/lib/calabash/cli/run.rb +99 -0
  57. data/lib/calabash/cli/setup_keystore.rb +39 -0
  58. data/lib/calabash/color.rb +32 -0
  59. data/lib/calabash/console_helpers.rb +90 -0
  60. data/lib/calabash/defaults.rb +56 -0
  61. data/lib/calabash/device.rb +401 -0
  62. data/lib/calabash/environment.rb +75 -0
  63. data/lib/calabash/gestures.rb +384 -0
  64. data/lib/calabash/http.rb +8 -0
  65. data/lib/calabash/http/error.rb +15 -0
  66. data/lib/calabash/http/request.rb +42 -0
  67. data/lib/calabash/http/retriable_client.rb +156 -0
  68. data/lib/calabash/interactions.rb +105 -0
  69. data/lib/calabash/ios.rb +37 -0
  70. data/lib/calabash/ios/application.rb +119 -0
  71. data/lib/calabash/ios/conditions.rb +79 -0
  72. data/lib/calabash/ios/console_helpers.rb +72 -0
  73. data/lib/calabash/ios/device.rb +24 -0
  74. data/lib/calabash/ios/device/device_implementation.rb +779 -0
  75. data/lib/calabash/ios/device/gestures_mixin.rb +167 -0
  76. data/lib/calabash/ios/device/keyboard_mixin.rb +133 -0
  77. data/lib/calabash/ios/device/physical_device_mixin.rb +266 -0
  78. data/lib/calabash/ios/device/rotation_mixin.rb +124 -0
  79. data/lib/calabash/ios/device/routes/backdoor_route_mixin.rb +86 -0
  80. data/lib/calabash/ios/device/routes/condition_route_mixin.rb +62 -0
  81. data/lib/calabash/ios/device/routes/error.rb +8 -0
  82. data/lib/calabash/ios/device/routes/handle_route_mixin.rb +102 -0
  83. data/lib/calabash/ios/device/routes/map_route_mixin.rb +38 -0
  84. data/lib/calabash/ios/device/routes/playback_route_mixin.rb +70 -0
  85. data/lib/calabash/ios/device/routes/response_parser.rb +48 -0
  86. data/lib/calabash/ios/device/routes/uia_route_mixin.rb +238 -0
  87. data/lib/calabash/ios/device/runtime_attributes.rb +184 -0
  88. data/lib/calabash/ios/device/status_bar_mixin.rb +17 -0
  89. data/lib/calabash/ios/device/text_mixin.rb +19 -0
  90. data/lib/calabash/ios/device/uia_keyboard_mixin.rb +188 -0
  91. data/lib/calabash/ios/device/uia_mixin.rb +12 -0
  92. data/lib/calabash/ios/environment.rb +41 -0
  93. data/lib/calabash/ios/interactions.rb +10 -0
  94. data/lib/calabash/ios/lib/.irbrc +55 -0
  95. data/lib/calabash/ios/lib/recordings/rotate_left_home_down_ipad.base64 +2 -0
  96. data/lib/calabash/ios/lib/recordings/rotate_left_home_down_iphone.base64 +2 -0
  97. data/lib/calabash/ios/lib/recordings/rotate_left_home_left_ipad.base64 +2 -0
  98. data/lib/calabash/ios/lib/recordings/rotate_left_home_left_iphone.base64 +2 -0
  99. data/lib/calabash/ios/lib/recordings/rotate_left_home_right_ipad.base64 +2 -0
  100. data/lib/calabash/ios/lib/recordings/rotate_left_home_right_iphone.base64 +2 -0
  101. data/lib/calabash/ios/lib/recordings/rotate_left_home_up_ipad.base64 +2 -0
  102. data/lib/calabash/ios/lib/recordings/rotate_left_home_up_iphone.base64 +2 -0
  103. data/lib/calabash/ios/lib/recordings/rotate_right_home_down_ipad.base64 +2 -0
  104. data/lib/calabash/ios/lib/recordings/rotate_right_home_down_iphone.base64 +2 -0
  105. data/lib/calabash/ios/lib/recordings/rotate_right_home_left_ipad.base64 +2 -0
  106. data/lib/calabash/ios/lib/recordings/rotate_right_home_left_iphone.base64 +2 -0
  107. data/lib/calabash/ios/lib/recordings/rotate_right_home_right_ipad.base64 +2 -0
  108. data/lib/calabash/ios/lib/recordings/rotate_right_home_right_iphone.base64 +2 -0
  109. data/lib/calabash/ios/lib/recordings/rotate_right_home_up_ipad.base64 +2 -0
  110. data/lib/calabash/ios/lib/recordings/rotate_right_home_up_iphone.base64 +2 -0
  111. data/lib/calabash/ios/orientation.rb +117 -0
  112. data/lib/calabash/ios/scroll.rb +504 -0
  113. data/lib/calabash/ios/server.rb +73 -0
  114. data/lib/calabash/ios/text.rb +248 -0
  115. data/lib/calabash/ios/uia.rb +24 -0
  116. data/lib/calabash/lib/skeleton/config/cucumber.yml +6 -0
  117. data/lib/calabash/lib/skeleton/features/sample.feature +5 -0
  118. data/lib/calabash/lib/skeleton/features/step_definitions/calabash_steps.rb +29 -0
  119. data/lib/calabash/lib/skeleton/features/support/env.rb +54 -0
  120. data/lib/calabash/lib/skeleton/features/support/hooks.rb +83 -0
  121. data/lib/calabash/life_cycle.rb +111 -0
  122. data/lib/calabash/location.rb +51 -0
  123. data/lib/calabash/logger.rb +87 -0
  124. data/lib/calabash/orientation.rb +84 -0
  125. data/lib/calabash/page.rb +35 -0
  126. data/lib/calabash/patch.rb +14 -0
  127. data/lib/calabash/patch/array.rb +16 -0
  128. data/lib/calabash/patch/run_loop.rb +90 -0
  129. data/lib/calabash/query.rb +160 -0
  130. data/lib/calabash/query_result.rb +85 -0
  131. data/lib/calabash/screenshot.rb +89 -0
  132. data/lib/calabash/server.rb +16 -0
  133. data/lib/calabash/text.rb +76 -0
  134. data/lib/calabash/utility.rb +58 -0
  135. data/lib/calabash/version.rb +3 -1
  136. data/lib/calabash/wait.rb +474 -0
  137. metadata +462 -24
@@ -0,0 +1,64 @@
1
+ module Calabash
2
+ # Contains the Android implementations of the Calabash APIs.
3
+ module Android
4
+ TEST_SERVER_CODE_PATH = File.join(File.dirname(__FILE__), '..', '..', 'android', 'test-server')
5
+ UNSIGNED_TEST_SERVER_APK = File.join(File.dirname(__FILE__), 'android', 'lib', 'TestServer.apk')
6
+ ANDROID_MANIFEST_PATH = File.join(File.dirname(__FILE__), 'android', 'lib', 'AndroidManifest.xml')
7
+
8
+ require 'calabash'
9
+ include Calabash
10
+
11
+ # @!visibility private
12
+ def self.extended(base)
13
+ Calabash.send(:extended, base)
14
+ end
15
+
16
+ # @!visibility private
17
+ def self.included(base)
18
+ Calabash.send(:included, base)
19
+ end
20
+
21
+ require 'calabash/android/environment'
22
+
23
+ require 'calabash/android/application'
24
+ require 'calabash/android/build'
25
+ require 'calabash/android/device'
26
+ require 'calabash/android/screenshot'
27
+ require 'calabash/android/server'
28
+ require 'calabash/android/adb'
29
+ require 'calabash/android/gestures'
30
+ require 'calabash/android/interactions'
31
+ require 'calabash/android/orientation'
32
+ require 'calabash/android/physical_buttons'
33
+ require 'calabash/android/text'
34
+ require 'calabash/android/console_helpers'
35
+ require 'calabash/android/life_cycle'
36
+
37
+ include Calabash::Android::Gestures
38
+ include Calabash::Android::Interactions
39
+ include Calabash::Android::LifeCycle
40
+ include Calabash::Android::Orientation
41
+ include Calabash::Android::PhysicalButtons
42
+ include Calabash::Android::Text
43
+
44
+ # @!visibility private
45
+ def self.binary_location(name, abi, using_pie)
46
+ binary_name = if using_pie
47
+ "#{name}-pie"
48
+ else
49
+ name
50
+ end
51
+
52
+ file = File.join(File.dirname(__FILE__), 'android', 'lib', name, abi, binary_name)
53
+
54
+ unless File.exist?(file)
55
+ raise "No such file '#{file}'"
56
+ end
57
+
58
+ file
59
+ end
60
+ end
61
+ end
62
+
63
+ # Setup environment on load
64
+ Calabash::Android::Environment.setup
@@ -0,0 +1,277 @@
1
+ require 'timeout'
2
+ require 'open3'
3
+
4
+ module Calabash
5
+ module Android
6
+ # @!visibility private
7
+ class ADB
8
+ # @!visibility private
9
+ class ADBCallError < StandardError
10
+ attr_reader :stderr, :stdout
11
+
12
+ def initialize(message, stderr=nil, stdout=nil)
13
+ super(message)
14
+
15
+ @stderr = stderr
16
+ @stdout = stdout
17
+ end
18
+ end
19
+
20
+ PROCESS_WAIT_TIME = 10
21
+
22
+ def self.open_pipe_with_timeout(timeout, *cmd, &block)
23
+ begin
24
+ i, o, e, t, pid = nil
25
+
26
+ Timeout.timeout(timeout, ProcessDidNotExitError) do
27
+ i, o, e, t = Open3.popen3(*cmd)
28
+ i.sync = true
29
+ o.sync = true
30
+ e.sync = true
31
+ pid = t.pid
32
+ block.call(i, o, e)
33
+
34
+ t.value.exitstatus
35
+ end
36
+ rescue ProcessDidNotExitError => _
37
+ raise ADBCallError, 'ADB process did not exit'
38
+ ensure
39
+ i.close unless i.nil? || i.closed?
40
+ o.close unless o.nil? || o.closed?
41
+ e.close unless e.nil? || e.closed?
42
+
43
+ if pid
44
+ begin
45
+ Process.kill(9, pid)
46
+ rescue Errno::ESRCH => _
47
+ # do nothing
48
+ end
49
+ end
50
+
51
+ t.join if t
52
+ end
53
+ end
54
+
55
+ def self.open_adb_pipe(*cmd, **options, &block)
56
+ timeout = options.fetch(:timeout, PROCESS_WAIT_TIME)
57
+
58
+ open_pipe_with_timeout(timeout, Environment.adb_path, *cmd) do |i, o, e|
59
+ block.call(i, o, e) if block
60
+ end
61
+ end
62
+
63
+ DAEMON_STARTED_MESSAGE = "* daemon not running. starting it now on port 5037 *\n* daemon started successfully *\n"
64
+
65
+ def self.command(*cmd, **args)
66
+ Logger.debug("ADB Command: #{cmd.join(', ')}")
67
+ Logger.debug("ADB input: #{args[:input]}")
68
+ stderr = nil
69
+ stdout = nil
70
+ exit_code = nil
71
+
72
+ input = args[:input]
73
+
74
+ begin
75
+ exit_code = open_adb_pipe(*cmd, args) do |i, o, e|
76
+ if input
77
+ input.each do |p_cmd|
78
+ begin
79
+ i.puts p_cmd
80
+ rescue Errno::EPIPE => err
81
+ i.close
82
+ stderr = e.readlines.join
83
+ stdout = o.readlines.join
84
+ raise ADBCallError.new(err, stderr, stdout)
85
+ end
86
+ end
87
+
88
+ i.close
89
+ end
90
+
91
+ unless args.fetch(:no_read, false)
92
+ stdout = o.readlines.join
93
+ stderr = e.readlines.join
94
+ end
95
+
96
+ if stdout && stdout.start_with?(DAEMON_STARTED_MESSAGE)
97
+ stdout = stdout[DAEMON_STARTED_MESSAGE.length..-1]
98
+ end
99
+ end
100
+ rescue IOError => e
101
+ raise ADBCallError, e
102
+ end
103
+
104
+ if exit_code != 0
105
+ Logger.debug("Adb process exited with #{exit_code}")
106
+ Logger.debug("Error message from ADB: ")
107
+ Logger.debug(stderr)
108
+
109
+ stderr_output = if stderr && !stderr.empty?
110
+ ": #{dot_string(stderr.lines.first, 100)}"
111
+ else
112
+ ''
113
+ end
114
+
115
+ raise ADBCallError.new(
116
+ "Adb process exited with #{exit_code}#{stderr_output}", stderr, stdout)
117
+ end
118
+
119
+ stdout
120
+ end
121
+
122
+ attr_reader :serial
123
+
124
+ def initialize(serial)
125
+ @serial = serial
126
+ end
127
+
128
+ def command(*argv, **args)
129
+ cmd = argv.dup
130
+
131
+ if serial
132
+ cmd.unshift('-s', serial)
133
+ end
134
+
135
+ ADB.command(*cmd, args)
136
+ end
137
+
138
+ END_STRING = '__CAL_END__'
139
+
140
+ def shell(shell_cmd, options={})
141
+ if shell_cmd.nil? || shell_cmd.empty?
142
+ raise ArgumentError, "Invalid shell command '#{shell_cmd}'"
143
+ end
144
+
145
+ input =
146
+ [
147
+ "#{shell_cmd}; echo \"#{END_STRING}$?\"; exit 0"
148
+ ]
149
+
150
+ args = options.merge(input: input)
151
+
152
+ result = command('shell', args)
153
+
154
+ # We get a result like this:
155
+ #
156
+ # [0] "getprop ro.build.version.release; echo \"\r\n",
157
+ # [1] "$?\"; exit 0\r\n",
158
+ # [2] "shell@hammerhead:/ $ getprop ro.build.version.release; echo \"\r\r\n",
159
+ # [3] "> $?\"; exit 0\r\r\n",
160
+ # [4] "4.4\r\n",
161
+ # [5] "\r\n",
162
+ # [6] "0\r\n"
163
+ #
164
+ # out =
165
+ # [4] "4.4\r\n"
166
+ # [5] "\r\n",
167
+ # [6] "0\r\n"
168
+ #
169
+ # command_result =
170
+ # [4] "4.4\r\n"
171
+ # [5] "\r\n",
172
+ #
173
+ # exit_code_s =
174
+ # [6] "0\r\n"
175
+
176
+ index = result.lines.index {|line| line.start_with?(shell_name)}
177
+
178
+ if index.nil?
179
+ raise ADBCallError.new("Could not parse output #{ADB.dot_string(result, 100)}", result)
180
+ end
181
+
182
+ # Remove the commands
183
+ out = result.lines[index+1..-1]
184
+
185
+ last_line = out.last
186
+ end_index = nil
187
+
188
+ 15.times do |i|
189
+ if last_line[-(END_STRING.length+i-1)..-i] == END_STRING
190
+ end_index = -i
191
+ break
192
+ end
193
+ end
194
+
195
+ if end_index.nil?
196
+ raise ADBCallError.new("Could not parse output #{ADB.dot_string(result, 100)}", result)
197
+ end
198
+
199
+ # Get the result from the command
200
+ command_result = out[0..-2].join + last_line[0..(end_index - END_STRING.length)]
201
+
202
+ # Get the exit code
203
+ exit_code_s = out[-1][end_index+1..-1]
204
+
205
+ unless options[:no_exit_code_check]
206
+ unless exit_code_s.to_i.to_s == exit_code_s.chomp
207
+ raise ADBCallError,
208
+ "Unable to obtain exit code. Result: '#{exit_code_s}'"
209
+ end
210
+
211
+ exit_code = exit_code_s.to_i
212
+
213
+ if exit_code != 0
214
+ Logger.debug("Adb shell command exited with #{exit_code}")
215
+ Logger.debug("Error message from ADB: ")
216
+ Logger.debug(command_result)
217
+
218
+ stderr_output = if command_result && !command_result.empty?
219
+ ": #{ADB.dot_string(command_result.lines.first, 100)}"
220
+ else
221
+ ''
222
+ end
223
+
224
+ raise ADBCallError.new(
225
+ "Adb shell command exited with #{exit_code}#{stderr_output}", command_result)
226
+ end
227
+ end
228
+
229
+ command_result
230
+ end
231
+
232
+ private
233
+
234
+ def self.dot_string(string, length)
235
+ if string.length > length
236
+ "#{string[0, length-3]}..."
237
+ else
238
+ string
239
+ end
240
+ end
241
+
242
+ def shell_name
243
+ if @shell_name
244
+ @shell_name
245
+ else
246
+ result = command('shell', input: ['echo "test"; exit 0'])
247
+
248
+ # result.lines =
249
+ # [
250
+ # [0] "echo \"foo\"; exit 0\r\n",
251
+ # [1] "shell@hammerhead:/ $ echo \"foo\"; exit 0\r\r\n",
252
+ # [2] "foo\r\n"
253
+ # ]
254
+ #
255
+ # OR
256
+ #
257
+ # result.lines =
258
+ # [
259
+ # [1] "shell@hammerhead:/ $ echo \"foo\"; exit 0\r\r\n",
260
+ # [2] "foo\r\n"
261
+ # ]
262
+
263
+ #result.lines.index {|line| !line.start_with?('echo')}
264
+
265
+ # "shell@hammerhead:/ $ echo \"foo\"; exit 0\r\r\n"
266
+ shell_name_line = result.lines[-2]
267
+
268
+ # "shell@hammerhead:/ $ "
269
+ @shell_name = shell_name_line.split('echo').first
270
+ end
271
+ end
272
+
273
+ # @!visibility private
274
+ class ProcessDidNotExitError < RuntimeError; end
275
+ end
276
+ end
277
+ end
@@ -0,0 +1,110 @@
1
+ module Calabash
2
+ module Android
3
+ # A class to represent an Android application (.apk).
4
+ class Application < Calabash::Application
5
+ attr_reader :test_server
6
+
7
+ def self.default_from_environment
8
+ application_path = Environment::APP_PATH
9
+
10
+ if application_path.nil?
11
+ raise 'No application path is set'
12
+ end
13
+
14
+ unless File.exist?(application_path)
15
+ raise "Application '#{application_path}' does not exist"
16
+ end
17
+
18
+ if File.directory?(application_path)
19
+ raise "Application '#{application_path}' is not a file"
20
+ end
21
+
22
+ build_test_server = Build::TestServer.new(application_path)
23
+ test_server_path = Environment::TEST_SERVER_PATH ||
24
+ build_test_server.path
25
+
26
+ unless File.exist?(test_server_path)
27
+ Logger.error "Test-server '#{test_server_path}' does not exist."
28
+ Logger.error "Build it using: 'calabash build \"#{application_path}\"'"
29
+ Logger.error ''
30
+ raise "Test-server '#{test_server_path}' does not exist."
31
+ end
32
+
33
+ Application.new(application_path, test_server_path)
34
+ end
35
+
36
+ def initialize(application_path, test_server_path, options = {})
37
+ super(application_path, options)
38
+ @test_server = Application.new(test_server_path, nil, options) if test_server_path
39
+ end
40
+
41
+ def extract_identifier
42
+ package_line = aapt_dump('package').first
43
+ raise "'package' not found in aapt output" unless package_line
44
+ m = package_line.match(/name='([^']+)'/)
45
+ raise "Unexpected output from aapt: #{package_line}" unless m
46
+ m[1]
47
+ end
48
+
49
+ def main_activity
50
+ begin
51
+ @logger.log("Trying to find launchable activity")
52
+ launchable_activity_line = aapt_dump('launchable-activity').first
53
+ raise "'launchable-activity' not found in aapt output" unless launchable_activity_line
54
+ m = launchable_activity_line.match(/name='([^']+)'/)
55
+ raise "Unexpected output from aapt: #{launchable_activity_line}" unless m
56
+ @logger.log("Found launchable activity '#{m[1]}'")
57
+ m[1]
58
+ rescue => e
59
+ @logger.log("Could not find launchable activity, trying to parse raw AndroidManifest. #{e.message}")
60
+
61
+ manifest_data = `"#{Environment.aapt_path}/aapt" dump xmltree "#{@path}" AndroidManifest.xml`
62
+ regex = /^\s*A:[\s*]android:name\(\w+\)\=\"android.intent.category.LAUNCHER\"/
63
+ lines = manifest_data.lines.collect(&:strip)
64
+ indicator_line = nil
65
+
66
+ lines.each_with_index do |line, index|
67
+ match = line.match(regex)
68
+
69
+ unless match.nil?
70
+ raise 'More than one launchable activity in AndroidManifest' unless indicator_line.nil?
71
+ indicator_line = index
72
+ end
73
+ end
74
+
75
+ raise 'No launchable activity found in AndroidManifest' unless indicator_line
76
+
77
+ intent_filter_found = false
78
+
79
+ (0..indicator_line).reverse_each do |index|
80
+ if intent_filter_found
81
+ match = lines[index].match(/\s*E:\s*activity-alias/)
82
+
83
+ raise 'Could not find target activity in activity alias' if match
84
+
85
+ match = lines[index].match(/^\s*A:\s*android:targetActivity\(\w*\)\=\"([^\"]+)/){$1}
86
+
87
+ if match
88
+ @logger.log("Found launchable activity '#{match}'")
89
+
90
+ return match
91
+ end
92
+ else
93
+ unless lines[index].match(/\s*E: intent-filter/).nil?
94
+ @logger.log("Read intent filter")
95
+ intent_filter_found = true
96
+ end
97
+ end
98
+ end
99
+
100
+ raise 'Could not find launchable activity'
101
+ end
102
+ end
103
+
104
+ def aapt_dump(key)
105
+ lines = `"#{Environment.aapt_path}" dump badging "#{path}"`.lines.collect(&:strip)
106
+ lines.select { |l| l.start_with?("#{key}:") }
107
+ end
108
+ end
109
+ end
110
+ end