bubble-wrap 1.7.1 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -1
  3. data/.travis.yml +1 -1
  4. data/GETTING_STARTED.md +1 -1
  5. data/Gemfile.lock +10 -10
  6. data/README.md +266 -122
  7. data/Rakefile +1 -1
  8. data/bubble-wrap.gemspec +7 -6
  9. data/lib/bubble-wrap.rb +0 -1
  10. data/lib/bubble-wrap/all.rb +13 -1
  11. data/lib/bubble-wrap/location.rb +1 -1
  12. data/lib/bubble-wrap/motion.rb +10 -0
  13. data/lib/bubble-wrap/rss_parser.rb +0 -1
  14. data/lib/bubble-wrap/test.rb +1 -0
  15. data/lib/bubble-wrap/version.rb +1 -1
  16. data/motion/core/device/ios/camera.rb +12 -1
  17. data/motion/core/ios/device.rb +7 -1
  18. data/motion/core/json.rb +1 -1
  19. data/motion/core/osx/app.rb +11 -1
  20. data/motion/core/time.rb +27 -4
  21. data/motion/location/location.rb +6 -2
  22. data/motion/mail/mail.rb +4 -0
  23. data/motion/media/player.rb +2 -1
  24. data/motion/motion/motion.rb +421 -0
  25. data/motion/reactor/deferrable.rb +29 -3
  26. data/motion/reactor/eventable.rb +3 -1
  27. data/motion/reactor/thread_aware_deferrable.rb +37 -0
  28. data/motion/rss_parser.rb +11 -21
  29. data/motion/sms/sms.rb +4 -0
  30. data/motion/ui/ui_alert_view.rb +3 -1
  31. data/motion/ui/ui_control_wrapper.rb +27 -0
  32. data/motion/ui/ui_view_wrapper.rb +1 -7
  33. data/motion/util/constants.rb +1 -1
  34. data/samples/alert/Gemfile +1 -0
  35. data/samples/alert/Gemfile.lock +16 -0
  36. data/samples/alert/Rakefile +1 -1
  37. data/samples/camera/Gemfile +2 -1
  38. data/samples/camera/Gemfile.lock +16 -0
  39. data/samples/camera/Rakefile +1 -1
  40. data/samples/gesture/Gemfile +2 -1
  41. data/samples/gesture/Gemfile.lock +9 -3
  42. data/samples/gesture/Rakefile +1 -1
  43. data/samples/location/Gemfile +3 -1
  44. data/samples/location/Gemfile.lock +18 -0
  45. data/samples/location/Rakefile +4 -2
  46. data/samples/location/app/controllers/{image_list_controller.rb → places_list_controller.rb} +0 -0
  47. data/samples/media/Gemfile +4 -0
  48. data/samples/media/Gemfile.lock +16 -0
  49. data/samples/media/Rakefile +1 -1
  50. data/samples/osx/Gemfile +3 -1
  51. data/samples/osx/Gemfile.lock +5 -1
  52. data/spec/lib/bubble-wrap/requirement_spec.rb +2 -2
  53. data/spec/motion/core/app_spec.rb +23 -0
  54. data/spec/motion/core/device/ios/camera_spec.rb +1 -1
  55. data/spec/motion/core/device/ios/device_spec.rb +6 -0
  56. data/spec/motion/core/ios/app_spec.rb +9 -24
  57. data/spec/motion/core/json_spec.rb +30 -10
  58. data/spec/motion/core/osx/app_spec.rb +2 -1
  59. data/spec/motion/core/time_spec.rb +34 -1
  60. data/spec/motion/location/location_spec.rb +6 -0
  61. data/spec/motion/mail/mail_spec.rb +20 -16
  62. data/spec/motion/motion/core_motion_spec.rb +231 -0
  63. data/spec/motion/reactor/deferrable_spec.rb +81 -0
  64. data/spec/motion/reactor/eventable_spec.rb +11 -0
  65. data/spec/motion/reactor/thread_aware_deferrable_spec.rb +85 -0
  66. data/spec/motion/rss_parser_spec.rb +11 -21
  67. data/spec/motion/sms/sms_spec.rb +11 -6
  68. data/spec/motion/ui/ui_alert_view_spec.rb +23 -0
  69. data/spec/motion/ui/ui_control_wrapper_spec.rb +24 -0
  70. metadata +58 -38
  71. data/lib/bubble-wrap/http.rb +0 -7
data/Rakefile CHANGED
@@ -28,7 +28,7 @@ Motion::Project::App.setup do |app|
28
28
  app.spec_files
29
29
  if Motion::Project::App.osx?
30
30
  app.spec_files -= Dir.glob("./spec/motion/**/ios/**.rb")
31
- ["font", "location", "media", "ui", "mail", "sms", "network-indicator"].each do |package|
31
+ ["font", "motion", "location", "media", "ui", "mail", "sms", "network-indicator"].each do |package|
32
32
  app.spec_files -= Dir.glob("./spec/motion/#{package}/**/*.rb")
33
33
  end
34
34
  else
data/bubble-wrap.gemspec CHANGED
@@ -3,10 +3,11 @@ require File.expand_path('../lib/bubble-wrap/version', __FILE__)
3
3
 
4
4
  Gem::Specification.new do |gem|
5
5
  gem.authors = ['Matt Aimonetti', 'Francis Chong', 'James Harton', 'Clay Allsopp', 'Dylan Markow', 'Jan Weinkauff', 'Marin Usalj']
6
- gem.email = ['mattaimonetti@gmail.com', 'francis@ignition.hk', 'james@sociable.co.nz', 'clay.allsopp@gmail.com', 'dylan@dylanmarkow.com', 'jan@dreimannzelt.de', 'mneorr@gmail.com']
6
+ gem.email = ['mattaimonetti@gmail.com', 'francis@ignition.hk', 'james@sociable.co.nz', 'clay.allsopp@gmail.com', 'dylan@dylanmarkow.com', 'jan@dreimannzelt.de', 'marin2211@gmail.com']
7
7
  gem.description = 'RubyMotion wrappers and helpers (Ruby for iOS and OS X) - Making Cocoa APIs more Ruby like, one API at a time. Fork away and send your pull request.'
8
8
  gem.summary = 'RubyMotion wrappers and helpers (Ruby for iOS and OS X) - Making Cocoa APIs more Ruby like, one API at a time. Fork away and send your pull request.'
9
9
  gem.homepage = 'http://rubymotion.github.io/BubbleWrap/'
10
+ gem.license = 'MIT'
10
11
 
11
12
  gem.files = `git ls-files`.split($\)
12
13
  gem.test_files = gem.files.grep(%r{^(test|spec|lib_spec|features)/})
@@ -16,9 +17,9 @@ Gem::Specification.new do |gem|
16
17
 
17
18
  gem.extra_rdoc_files = gem.files.grep(%r{motion})
18
19
 
19
- gem.add_dependency 'bubble-wrap-http', BubbleWrap::VERSION
20
- gem.add_development_dependency 'mocha', '0.11.4'
21
- gem.add_development_dependency 'mocha-on-bacon'
22
- gem.add_development_dependency 'bacon'
23
- gem.add_development_dependency 'rake'
20
+ gem.add_development_dependency 'mocha', '~> 0.11'
21
+ gem.add_development_dependency 'mocha-on-bacon', '~> 0.2'
22
+ gem.add_development_dependency 'bacon', '~> 1.2'
23
+ gem.add_development_dependency 'rake', '~> 10.0'
24
+ gem.add_development_dependency 'webstub', '~> 1.1'
24
25
  end
data/lib/bubble-wrap.rb CHANGED
@@ -1,3 +1,2 @@
1
1
  require 'bubble-wrap/version' unless defined?(BubbleWrap::VERSION)
2
2
  require File.expand_path('../bubble-wrap/core', __FILE__)
3
- require File.expand_path('../bubble-wrap/http', __FILE__)
@@ -1,4 +1,16 @@
1
1
  require File.expand_path('../loader', __FILE__)
2
- ['core', 'http', 'reactor', 'rss_parser', 'ui', 'location', 'media', 'font', 'mail','sms', 'network-indicator'].each { |sub|
2
+ [
3
+ 'core',
4
+ 'font',
5
+ 'location',
6
+ 'mail',
7
+ 'media',
8
+ 'motion',
9
+ 'network-indicator',
10
+ 'reactor',
11
+ 'rss_parser',
12
+ 'sms',
13
+ 'ui',
14
+ ].each { |sub|
3
15
  require File.expand_path("../#{sub}", __FILE__)
4
16
  }
@@ -8,4 +8,4 @@ BubbleWrap.require_ios("location") do
8
8
  file('motion/location/location.rb').depends_on 'motion/util/constants.rb'
9
9
  file('motion/location/location.rb').uses_framework('CoreLocation')
10
10
  end
11
- end
11
+ end
@@ -0,0 +1,10 @@
1
+ require 'bubble-wrap/loader'
2
+
3
+ BubbleWrap.require_ios('motion') do
4
+ BubbleWrap.require('motion/util/constants.rb')
5
+ BubbleWrap.require('motion/core/string.rb')
6
+ BubbleWrap.require('motion/motion/**/*.rb') do
7
+ file('motion/motion/motion.rb').depends_on 'motion/util/constants.rb'
8
+ file('motion/motion/motion.rb').uses_framework('CoreMotion')
9
+ end
10
+ end
@@ -1,3 +1,2 @@
1
1
  require 'bubble-wrap/loader'
2
2
  BubbleWrap.require('motion/rss_parser.rb')
3
- BubbleWrap.require('motion/http.rb')
@@ -1,3 +1,4 @@
1
+ require 'webstub'
1
2
  require 'bubble-wrap/loader'
2
3
  BW.require 'motion/util/*.rb'
3
4
  BW.require 'motion/test_suite_delegate.rb'
@@ -1,4 +1,4 @@
1
1
  module BubbleWrap
2
- VERSION = '1.7.1' unless defined?(BubbleWrap::VERSION)
2
+ VERSION = '1.8.0' unless defined?(BubbleWrap::VERSION)
3
3
  MIN_MOTION_VERSION = '2.17'
4
4
  end
@@ -15,6 +15,13 @@ module BubbleWrap
15
15
  Constants.register UIImagePickerControllerSourceTypePhotoLibrary, UIImagePickerControllerSourceTypeCamera,
16
16
  UIImagePickerControllerSourceTypeSavedPhotosAlbum
17
17
 
18
+ Constants.register UIImagePickerControllerQualityTypeHigh,
19
+ UIImagePickerControllerQualityTypeMedium,
20
+ UIImagePickerControllerQualityTypeLow,
21
+ UIImagePickerControllerQualityType640x480,
22
+ UIImagePickerControllerQualityTypeIFrame1280x720,
23
+ UIImagePickerControllerQualityTypeIFrame960x540
24
+
18
25
  MEDIA_TYPE_HASH = {movie: KUTTypeMovie, image: KUTTypeImage}
19
26
 
20
27
  CAMERA_LOCATIONS = [:front, :rear, :none]
@@ -98,7 +105,9 @@ module BubbleWrap
98
105
  animated: true,
99
106
  on_dismiss: false,
100
107
  media_types: [:image],
101
- dismiss_completed: nil
108
+ dismiss_completed: nil,
109
+ video_quality: :medium,
110
+ video_maximum_duration: 600
102
111
  }.merge(options)
103
112
 
104
113
  # If we're using Camera.any, by default use photo library
@@ -130,6 +139,8 @@ module BubbleWrap
130
139
  self.picker.sourceType = source_type
131
140
  self.picker.mediaTypes = media_types
132
141
  self.picker.allowsEditing = @options[:allows_editing]
142
+ self.picker.videoQuality = Constants.get("UIImagePickerControllerQualityType", @options[:video_quality])
143
+ self.picker.videoMaximumDuration = @options[:video_maximum_duration]
133
144
 
134
145
  if source_type_readable == :camera && ![:front, :rear].member?(self.location)
135
146
  raise Error::INVALID_CAMERA_LOCATION, "Can't use camera location #{self.location} with source type :camera"
@@ -51,6 +51,12 @@ module BubbleWrap
51
51
  UIDevice.currentDevice.systemVersion
52
52
  end
53
53
 
54
+ # Returns an identifier unique to the vendor across the vendors app.
55
+ # @return [NSUUID]
56
+ def vendor_identifier
57
+ UIDevice.currentDevice.identifierForVendor
58
+ end
59
+
54
60
  # Delegates to BubbleWrap::Screen.orientation
55
61
  def orientation
56
62
  screen.orientation
@@ -61,4 +67,4 @@ module BubbleWrap
61
67
  screen.interface_orientation
62
68
  end
63
69
  end
64
- end
70
+ end
data/motion/core/json.rb CHANGED
@@ -14,7 +14,7 @@ module BubbleWrap
14
14
  # TODO: support options like the C Ruby module does
15
15
  def self.parse(str_data, &block)
16
16
  return nil unless str_data
17
- data = str_data.respond_to?(:to_data) ? str_data.to_data : str_data
17
+ data = str_data.respond_to?('dataUsingEncoding:') ? str_data.dataUsingEncoding(NSUTF8StringEncoding) : str_data
18
18
  opts = NSJSONReadingMutableContainers | NSJSONReadingMutableLeaves | NSJSONReadingAllowFragments
19
19
  error = Pointer.new(:id)
20
20
  obj = NSJSONSerialization.JSONObjectWithData(data, options:opts, error:error)
@@ -2,6 +2,15 @@ module BubbleWrap
2
2
  module App
3
3
  module_function
4
4
 
5
+ # Opens an url (string or instance of `NSURL`)
6
+ # in the default web browser
7
+ # Usage Example:
8
+ # App.open_url("http://www.rubymotion.com")
9
+ def open_url(url)
10
+ url = NSURL.URLWithString(url) unless url.is_a?(NSURL)
11
+ NSWorkspace.sharedWorkspace.openURL(url)
12
+ end
13
+
5
14
  # Application Delegate
6
15
  def delegate
7
16
  shared.delegate
@@ -11,5 +20,6 @@ module BubbleWrap
11
20
  def shared
12
21
  NSApplication.sharedApplication
13
22
  end
23
+
14
24
  end
15
- end
25
+ end
data/motion/core/time.rb CHANGED
@@ -1,25 +1,48 @@
1
1
  class Time
2
-
2
+
3
3
  def self.iso8601(time)
4
+ if time.include?(".")
5
+ # Fractional Seconds
6
+ if time.include?('Z')
7
+ iso8601_with_fractional_seconds(time)
8
+ else
9
+ iso8601_with_fractional_seconds_and_timesone(time)
10
+ end
11
+ else
12
+ # Non Fractional Seconds
13
+ if time.include?('Z')
14
+ iso8601_zulu(time)
15
+ else
16
+ iso8601_with_timezone(time)
17
+ end
18
+ end
19
+ end
20
+
21
+ def self.iso8601_zulu(time)
4
22
  cached_date_formatter("yyyy-MM-dd'T'HH:mm:ss'Z'").
5
23
  dateFromString(time)
6
24
  end
7
-
25
+
8
26
  def self.iso8601_with_timezone(time)
9
27
  cached_date_formatter("yyyy-MM-dd'T'HH:mm:ssZZZZZ").
10
28
  dateFromString(time)
11
29
  end
12
-
30
+
13
31
  def self.iso8601_with_fractional_seconds(time)
14
32
  cached_date_formatter("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").
15
33
  dateFromString(time)
16
34
  end
17
35
 
36
+ def self.iso8601_with_fractional_seconds_and_timesone(time)
37
+ cached_date_formatter("yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ").
38
+ dateFromString(time)
39
+ end
40
+
18
41
  private
19
42
 
20
43
  def self.cached_date_formatter(dateFormat)
21
44
  Thread.current[:date_formatters] ||= {}
22
- Thread.current[:date_formatters][dateFormat] ||=
45
+ Thread.current[:date_formatters][dateFormat] ||=
23
46
  NSDateFormatter.alloc.init.tap do |formatter|
24
47
  formatter.dateFormat = dateFormat
25
48
  formatter.timeZone = NSTimeZone.timeZoneWithAbbreviation "UTC"
@@ -25,6 +25,10 @@ module BubbleWrap
25
25
  KCLLocationAccuracyNearestTenMeters, KCLLocationAccuracyHundredMeters,
26
26
  KCLLocationAccuracyKilometer, KCLLocationAccuracyThreeKilometers
27
27
 
28
+ # New additions to CLAuthorizationStatus in ios8
29
+ # see: https://developer.apple.com/library/prerelease/ios/documentation/CoreLocation/Reference/CLLocationManager_Class/index.html#//apple_ref/c/tdef/CLAuthorizationStatus
30
+ Constants.register KCLAuthorizationStatusAuthorizedWhenInUse, KCLAuthorizationStatusAuthorizedAlways
31
+
28
32
  module_function
29
33
  # Start getting locations
30
34
  # @param [Hash] options = {
@@ -150,14 +154,14 @@ module BubbleWrap
150
154
  @location_manager
151
155
  end
152
156
 
153
- # returns true/false whether services are enabled for the _device_
157
+ # returns true/false whether services, or limited services, are enabled for the _device_
154
158
  def enabled?
155
159
  CLLocationManager.locationServicesEnabled
156
160
  end
157
161
 
158
162
  # returns true/false whether services are enabled for the _app_
159
163
  def authorized?
160
- CLLocationManager.authorizationStatus == KCLAuthorizationStatusAuthorized
164
+ [KCLAuthorizationStatusAuthorized, KCLAuthorizationStatusAuthorizedAlways, KCLAuthorizationStatusAuthorizedWhenInUse].include?(CLLocationManager.authorizationStatus)
161
165
  end
162
166
 
163
167
  def error(type)
data/motion/mail/mail.rb CHANGED
@@ -56,6 +56,10 @@ module BubbleWrap
56
56
  mail_controller
57
57
  end
58
58
 
59
+ def can_send_mail?
60
+ !!MFMailComposeViewController.canSendMail
61
+ end
62
+
59
63
  # Event when the MFMailComposeViewController is closed
60
64
  # -------------------------------------------------------------
61
65
  # the callback is fired if it was present in the constructor
@@ -73,11 +73,12 @@ module BubbleWrap
73
73
  klass = display_modal ? MPMoviePlayerViewController : MPMoviePlayerController
74
74
 
75
75
  content_url = content_url.is_a?(NSURL) ? content_url : NSURL.URLWithString(content_url)
76
- @media_player = klass.alloc.initWithContentURL(content_url)
76
+ @media_player = klass.alloc.init
77
77
 
78
78
  self.media_player.prepareToPlay if not display_modal
79
79
 
80
80
  set_player_options(options)
81
+ self.media_player.setContentURL(content_url)
81
82
 
82
83
  NSNotificationCenter.defaultCenter.observe MPMoviePlayerPlaybackDidFinishNotification do |notification|
83
84
  h = notification.userInfo
@@ -0,0 +1,421 @@
1
+ # Provides a nice DSL for interacting with the standard CMMotionManager from
2
+ # CoreMotion
3
+ module BubbleWrap
4
+ # These module methods provide the main interface. It uses a shared manager
5
+ # (per Apple's recommendation), and they all have a common set of supported
6
+ # methods:
7
+ # available?
8
+ # active?
9
+ # repeat(opts)
10
+ # once(opts)
11
+ # every(time_interval, opts)
12
+ #
13
+ # @example
14
+ # if BW::Motion.accelerometer.available?
15
+ # BW::Motion.accelerometer.every(5) do |result|
16
+ # # see the README for the keys that are available in result.
17
+ # end
18
+ # end
19
+ #
20
+ # If you insist on using your own manager, or you want more than one
21
+ # BW::Motion::Whatever running at the same time, you'll need to instantiate
22
+ # them yourself.
23
+ #
24
+ # @example
25
+ # mgr = CMMotionManager.alloc.init
26
+ # accel = BW::Motion::Accelerometer.new(mgr)
27
+ # accel.once do |result_data|
28
+ # end
29
+ # # => BW::Motion::accelerometer.once do |result_data| ... end
30
+ module Motion
31
+ module_function
32
+
33
+ def manager
34
+ @manager ||= CMMotionManager.alloc.init
35
+ end
36
+
37
+ def accelerometer
38
+ @accelerometer ||= Accelerometer.new(self.manager)
39
+ end
40
+
41
+ def gyroscope
42
+ @gyroscope ||= Gyroscope.new(self.manager)
43
+ end
44
+
45
+ def magnetometer
46
+ @magnetometer ||= Magnetometer.new(self.manager)
47
+ end
48
+
49
+ def device
50
+ @device ||= DeviceMotion.new(self.manager)
51
+ end
52
+ end
53
+
54
+
55
+ module Motion
56
+ module Error
57
+ end
58
+
59
+ class GenericMotionInterface
60
+
61
+ def initialize(manager)
62
+ @manager = manager
63
+ end
64
+
65
+ def repeat(options={}, &blk)
66
+ raise "A block is required" unless blk
67
+ blk.weak! if BubbleWrap.use_weak_callbacks?
68
+
69
+ self.start(options, &blk)
70
+ return self
71
+ end
72
+
73
+ def every(time=nil, options={}, &blk)
74
+ raise "A block is required" unless blk
75
+ blk.weak! if BubbleWrap.use_weak_callbacks?
76
+
77
+ if time.is_a?(NSDictionary)
78
+ options = time
79
+ elsif time
80
+ options = options.merge(interval: time)
81
+ end
82
+
83
+ self.start(options, &blk)
84
+ return self
85
+ end
86
+
87
+ def once(options={}, &blk)
88
+ raise "A block is required" unless blk
89
+ blk.weak! if BubbleWrap.use_weak_callbacks?
90
+
91
+ @called_once = false
92
+ every(options) do |result, error|
93
+ unless @called_once
94
+ @called_once = true
95
+ blk.call(result, error)
96
+ end
97
+ self.stop
98
+ end
99
+
100
+ return self
101
+ end
102
+
103
+ private def convert_queue(queue_name)
104
+ case queue_name
105
+ when :main, nil
106
+ return NSOperationQueue.mainQueue
107
+ when :background
108
+ queue = NSOperationQueue.new
109
+ queue.name = 'com.bubble-wrap.core-motion.background-queue'
110
+ return queue
111
+ when :current
112
+ return NSOperationQueue.currentQueue
113
+ when String
114
+ queue = NSOperationQueue.new
115
+ queue.name = queue_name
116
+ return queue
117
+ else
118
+ queue_name
119
+ end
120
+ end
121
+
122
+ private def internal_handler(handler)
123
+ retval = -> (result_data, error) do
124
+ handle_result(result_data, error, handler)
125
+ end
126
+ retval.weak! if BubbleWrap.use_weak_callbacks?
127
+ retval
128
+ end
129
+
130
+ end
131
+
132
+ class Accelerometer < GenericMotionInterface
133
+
134
+ def start(options={}, &handler)
135
+ if options.key?(:interval)
136
+ @manager.accelerometerUpdateInterval = options[:interval]
137
+ end
138
+
139
+ if handler
140
+ queue = convert_queue(options[:queue])
141
+ @manager.startAccelerometerUpdatesToQueue(queue, withHandler: internal_handler(handler))
142
+ else
143
+ @manager.startAccelerometerUpdates
144
+ end
145
+
146
+ return self
147
+ end
148
+
149
+ private def handle_result(result_data, error, handler)
150
+ if result_data
151
+ result = {
152
+ data: result_data,
153
+ acceleration: result_data.acceleration,
154
+ x: result_data.acceleration.x,
155
+ y: result_data.acceleration.y,
156
+ z: result_data.acceleration.z,
157
+ }
158
+ else
159
+ result = nil
160
+ end
161
+
162
+ handler.call(result, error)
163
+ end
164
+
165
+ def available?
166
+ @manager.accelerometerAvailable?
167
+ end
168
+
169
+ def active?
170
+ @manager.accelerometerActive?
171
+ end
172
+
173
+ def data
174
+ @manager.accelerometerData
175
+ end
176
+
177
+ def stop
178
+ @manager.stopAccelerometerUpdates
179
+ end
180
+
181
+ end
182
+
183
+ class Gyroscope < GenericMotionInterface
184
+
185
+ def start(options={}, &handler)
186
+ if options.key?(:interval)
187
+ @manager.gyroUpdateInterval = options[:interval]
188
+ end
189
+
190
+ if handler
191
+ queue = convert_queue(options[:queue])
192
+ @manager.startGyroUpdatesToQueue(queue, withHandler: internal_handler(handler))
193
+ else
194
+ @manager.startGyroUpdates
195
+ end
196
+
197
+ return self
198
+ end
199
+
200
+ private def handle_result(result_data, error, handler)
201
+ if result_data
202
+ result = {
203
+ data: result_data,
204
+ rotation: result_data.rotationRate,
205
+ x: result_data.rotationRate.x,
206
+ y: result_data.rotationRate.y,
207
+ z: result_data.rotationRate.z,
208
+ }
209
+ else
210
+ result = nil
211
+ end
212
+
213
+ handler.call(result, error)
214
+ end
215
+
216
+ def available?
217
+ @manager.gyroAvailable?
218
+ end
219
+
220
+ def active?
221
+ @manager.gyroActive?
222
+ end
223
+
224
+ def data
225
+ @manager.gyroData
226
+ end
227
+
228
+ def stop
229
+ @manager.stopGyroUpdates
230
+ end
231
+
232
+ end
233
+
234
+ class Magnetometer < GenericMotionInterface
235
+
236
+ def start(options={}, &handler)
237
+ if options.key?(:interval)
238
+ @manager.magnetometerUpdateInterval = options[:interval]
239
+ end
240
+
241
+ if handler
242
+ queue = convert_queue(options[:queue])
243
+ @manager.startMagnetometerUpdatesToQueue(queue, withHandler: internal_handler(handler))
244
+ else
245
+ @manager.startMagnetometerUpdates
246
+ end
247
+
248
+ return self
249
+ end
250
+
251
+ private def handle_result(result_data, error, handler)
252
+ if result_data
253
+ result = {
254
+ data: result_data,
255
+ field: result_data.magneticField,
256
+ x: result_data.magneticField.x,
257
+ y: result_data.magneticField.y,
258
+ z: result_data.magneticField.z,
259
+ }
260
+ else
261
+ result = nil
262
+ end
263
+
264
+ handler.call(result, error)
265
+ end
266
+
267
+ def available?
268
+ @manager.magnetometerAvailable?
269
+ end
270
+
271
+ def active?
272
+ @manager.magnetometerActive?
273
+ end
274
+
275
+ def data
276
+ @manager.magnetometerData
277
+ end
278
+
279
+ def stop
280
+ @manager.stopMagnetometerUpdates
281
+ end
282
+
283
+ end
284
+
285
+ class DeviceMotion < GenericMotionInterface
286
+
287
+ def start(options={}, &handler)
288
+ if options.key?(:interval)
289
+ @manager.deviceMotionUpdateInterval = options[:interval]
290
+ end
291
+
292
+ if options.key?(:reference)
293
+ reference_frame = convert_reference_frame(options[:reference])
294
+ else
295
+ reference_frame = nil
296
+ end
297
+
298
+ if handler
299
+ queue = convert_queue(options[:queue])
300
+
301
+ if reference_frame
302
+ @manager.startDeviceMotionUpdatesUsingReferenceFrame(reference_frame, toQueue: queue, withHandler: internal_handler(handler))
303
+ else
304
+ @manager.startDeviceMotionUpdatesToQueue(queue, withHandler: internal_handler(handler))
305
+ end
306
+ else
307
+ if reference_frame
308
+ @manager.startDeviceMotionUpdatesUsingReferenceFrame(reference_frame)
309
+ else
310
+ @manager.startDeviceMotionUpdates
311
+ end
312
+ end
313
+
314
+ return self
315
+ end
316
+
317
+ private def handle_result(result_data, error, handler)
318
+ if result_data
319
+ result = {
320
+ data: result_data,
321
+ attitude: result_data.attitude,
322
+ rotation: result_data.rotationRate,
323
+ gravity: result_data.gravity,
324
+ acceleration: result_data.userAcceleration,
325
+ magnetic: result_data.magneticField,
326
+ }
327
+
328
+ if result_data.attitude
329
+ result.merge!({
330
+ roll: result_data.attitude.roll,
331
+ pitch: result_data.attitude.pitch,
332
+ yaw: result_data.attitude.yaw,
333
+ matrix: result_data.attitude.rotationMatrix,
334
+ quaternion: result_data.attitude.quaternion,
335
+ })
336
+ end
337
+
338
+ if result_data.rotationRate
339
+ result.merge!({
340
+ rotation_x: result_data.rotationRate.x,
341
+ rotation_y: result_data.rotationRate.y,
342
+ rotation_z: result_data.rotationRate.z,
343
+ })
344
+ end
345
+
346
+ if result_data.gravity
347
+ result.merge!({
348
+ gravity_x: result_data.gravity.x,
349
+ gravity_y: result_data.gravity.y,
350
+ gravity_z: result_data.gravity.z,
351
+ })
352
+ end
353
+
354
+ if result_data.userAcceleration
355
+ result.merge!({
356
+ acceleration_x: result_data.userAcceleration.x,
357
+ acceleration_y: result_data.userAcceleration.y,
358
+ acceleration_z: result_data.userAcceleration.z,
359
+ })
360
+ end
361
+
362
+ if result_data.magneticField
363
+ case result_data.magneticField.accuracy
364
+ when CMMagneticFieldCalibrationAccuracyLow
365
+ accuracy = :low
366
+ when CMMagneticFieldCalibrationAccuracyMedium
367
+ accuracy = :medium
368
+ when CMMagneticFieldCalibrationAccuracyHigh
369
+ accuracy = :high
370
+ end
371
+
372
+ result.merge!({
373
+ field: result_data.magneticField.field,
374
+ magnetic_x: result_data.magneticField.field.x,
375
+ magnetic_y: result_data.magneticField.field.y,
376
+ magnetic_z: result_data.magneticField.field.z,
377
+ magnetic_accuracy: accuracy,
378
+ })
379
+ end
380
+ else
381
+ result = nil
382
+ end
383
+
384
+ handler.call(result, error)
385
+ end
386
+
387
+ def convert_reference_frame(reference_frame)
388
+ case reference_frame
389
+ when :arbitrary_z
390
+ CMAttitudeReferenceFrameXArbitraryZVertical
391
+ when :corrected_z
392
+ CMAttitudeReferenceFrameXArbitraryCorrectedZVertical
393
+ when :magnetic_north
394
+ CMAttitudeReferenceFrameXMagneticNorthZVertical
395
+ when :true_north
396
+ CMAttitudeReferenceFrameXTrueNorthZVertical
397
+ else
398
+ reference_frame
399
+ end
400
+ end
401
+
402
+ def available?
403
+ @manager.deviceMotionAvailable?
404
+ end
405
+
406
+ def active?
407
+ @manager.deviceMotionActive?
408
+ end
409
+
410
+ def data
411
+ @manager.deviceMotion
412
+ end
413
+
414
+ def stop
415
+ @manager.stopDeviceMotionUpdates
416
+ end
417
+
418
+ end
419
+
420
+ end
421
+ end