bubble-wrap 1.7.1 → 1.8.0

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.
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