Compare commits

..

2 Commits

Author SHA1 Message Date
Yuan Zhu 4259a1cc92 Update pod spec version number. 2016-05-24 10:54:15 -07:00
Ben DiFrancesco 70d4532d0e Declare ORKScrollToTopAnimationDuration and ORKCGFloatInvalidValue as extern in ORKHelpers.h; fixes #679 2016-05-24 10:53:53 -07:00
789 changed files with 5912 additions and 27899 deletions
+59 -67
View File
@@ -1,8 +1,8 @@
ResearchKit Framework
===========
The *ResearchKit™ framework* is an open source software framework that makes it easy to create apps
for medical research or for other research projects.
The ResearchKit™ framework is an open source software framework that makes it easy to
create apps for medical research or for other research projects.
* [Getting Started](#gettingstarted)
* Documentation:
@@ -16,48 +16,36 @@ for medical research or for other research projects.
Getting More Information
========================
* Join the [*ResearchKit* Forum](https://forums.developer.apple.com/community/researchkit) for discussing uses of the *ResearchKit framework and* related projects.
* Join the [ResearchKit Forum](https://forums.developer.apple.com/community/researchkit) for discussing uses of the ResearchKit framework and related projects.
Use Cases
===========
A task in the *ResearchKit framework* contains a set of steps to present to a user. Everything,
whether its a *survey*, the *consent process*, or *active tasks*, is represented as a task that can
be presented with a task view controller.
A task in the ResearchKit framework contains a set of steps to present to a
user. Everything, whether its a survey, the consent process, or active tasks,
is represented as a task that can be presented with a task view controller.
Surveys
-------
The *ResearchKit framework* provides a pre-built user interface for surveys, which can be presented
modally on an *iPhone*, *iPod Touch*, or *iPad*. See
*[Creating Surveys](http://researchkit.org/docs/docs/Survey/CreatingSurveys.html)* for more
information.
The ResearchKit framework provides a pre-built user interface for surveys, which can be
presented modally on an iPhone, iPod Touch, or iPad. See *[Creating Surveys](http://researchkit.org/docs/docs/Survey/CreatingSurveys.html)* for more information.
Consent
----------------
The *ResearchKit framework* provides visual consent templates that you can customize to explain the
details of your research study and obtain a signature if needed.
See *[Obtaining Consent](http://researchkit.org/docs/docs/InformedConsent/InformedConsent.html)* for
more information.
The ResearchKit framework provides visual consent templates that you can customize to
explain the details of your research study and obtain a signature if needed. See *[Obtaining Consent](http://researchkit.org/docs/docs/InformedConsent/InformedConsent.html)* for more information.
Active Tasks
------------
Some studies may need data beyond survey questions or the passive data collection capabilities
available through use of the *HealthKit* and *CoreMotion* APIs if you are programming for *iOS*.
*ResearchKit*'s active tasks invite users to perform activities under semi-controlled conditions,
while *iPhone* sensors actively collect data. See
*[Active Tasks](http://researchkit.org/docs/docs/ActiveTasks/ActiveTasks.html)* for more
information.
Charts
------------
*ResearchKit* includes a *Charts module*. It features three chart types: a *pie chart* (`ORKPieChartView`), a *line graph chart* (`ORKLineGraphChartView`), and a *discrete graph chart* (`ORKDiscreteGraphChartView`).
The views in the *Charts module* can be used independently of the rest of *ResearchKit*. They don't automatically connect with any other part of *ResearchKit*: the developer has to supply the data to be displayed through the views' `dataSources`, which allows for maximum flexibility.
Some studies may need data beyond survey questions or the passive data collection
capabilities available through use of the HealthKit and CoreMotion APIs if you are
programming for iOS. ResearchKit's active tasks invite users to perform activities
under semi-controlled conditions, while iPhone sensors actively collect data. See *[Active Tasks](http://researchkit.org/docs/docs/ActiveTasks/ActiveTasks.html)* for more information.
Getting Started<a name="gettingstarted"></a>
@@ -67,15 +55,16 @@ Getting Started<a name="gettingstarted"></a>
Requirements
------------
The primary *ResearchKit framework* codebase supports *iOS* and requires *Xcode 8.0* or newer. The
*ResearchKit framework* has a *Base SDK* version of *8.0*, meaning that apps using the *ResearchKit
framework* can run on devices with *iOS 8.0* or newer.
The primary ResearchKit framework codebase supports iOS and requires Xcode 7.0
or newer.
The ResearchKit framework has a Base SDK version of 8.0, meaning that apps
using the ResearchKit framework can run on devices with iOS 8.0 or newer.
Installation
------------
The latest stable version of *ResearchKit framework* can be cloned with
The latest stable version of ResearchKit framework can be cloned with
```
git clone -b stable https://github.com/ResearchKit/ResearchKit.git
@@ -90,49 +79,48 @@ git clone https://github.com/ResearchKit/ResearchKit.git
Building
--------
Build the *ResearchKit framework* by opening `ResearchKit.xcodeproj` and running the `ResearchKit`
framework target. Optionally, run the unit tests too.
Build the ResearchKit framework by opening `ResearchKit.xcodeproj` and running the
`ResearchKit` framework target. Optionally, run the unit tests too.
Adding the ResearchKit framework to your App
------------------------------
This walk-through shows how to embed the *ResearchKit framework* in your app as a dynamic framework,
and present a simple task view controller.
This walk-through shows how to embed the ResearchKit framework in your app as a
dynamic framework, and present a simple task view controller.
### 1. Add the ResearchKit framework to Your Project
###1. Add the ResearchKit framework to Your Project
To get started, drag `ResearchKit.xcodeproj` from your checkout into your *iOS* app project
in *Xcode*:
To get started, drag `ResearchKit.xcodeproj` from your checkout into
your iOS app project in Xcode:
<center>
<figure>
<img src="../../wiki/AddingResearchKitXcode.png" alt="Adding the ResearchKit framework to your
project" align="middle"/>
<img src="../../wiki/AddingResearchKitXcode.png" alt="Adding the ResearchKit framework to your project" align="middle"/>
</figure>
</center>
Then, embed the *ResearchKit framework* as a dynamic framework in your app, by adding it to the
*Embedded Binaries* section of the *General* pane for your target as shown in the figure below.
Then, embed the ResearchKit framework as a dynamic framework in your app, by adding
it to the Embedded Binaries section of the General pane for your
target as shown in the figure below.
<center>
<figure>
<img src="../../wiki/AddedBinaries.png" width="100%" alt="Adding the ResearchKit framework to
Embedded Binaries" align="middle"/>
<img src="../../wiki/AddedBinaries.png" width="100%" alt="Adding the ResearchKit framework to Embedded Binaries" align="middle"/>
<figcaption><center>Adding the ResearchKit framework to Embedded Binaries</center></figcaption>
</figure>
</center>
Note: You can also import *ResearchKit* into your project using a
[dependency manager](./docs-standalone/dependency-management.md) such as *CocoaPods* or *Carthage*.
Note: You can also import ResearchKit into your project using a [dependency manager](./docs-standalone/dependency-management.md) such as CocoaPods or Carthage.
### 2. Create a Step
###2. Create a Step
In this walk-through, we will use the *ResearchKit framework* to modally present a simple
single-step task showing a single instruction.
In this walk-through, we will use the ResearchKit framework to modally present a
simple single-step task showing a single instruction.
Create a step for your task by adding some code, perhaps in `viewDidAppear:` of an existing view
controller. To keep things simple, we'll use an instruction step (`ORKInstructionStep`) and name
Create a step for your task by adding some code, perhaps in
`viewDidAppear:` of an existing view controller. To keep things
simple, we'll use an instruction step (`ORKInstructionStep`) and name
the step `myStep`.
*Objective-C*
@@ -150,11 +138,12 @@ let myStep = ORKInstructionStep(identifier: "intro")
myStep.title = "Welcome to ResearchKit"
```
### 3. Create a Task
###3. Create a Task
Use the ordered task class (`ORKOrderedTask`) to create a task that contains `myStep`. An ordered
task is just a task where the order and selection of later steps does not depend on the results of
earlier ones. Name your task `task` and initialize it with `myStep`.
Use the ordered task class (`ORKOrderedTask`) to create a task that
contains `myStep`. An ordered task is just a task where the order and
selection of later steps does not depend on the results of earlier
ones. Name your task `task` and initialize it with `myStep`.
*Objective-C*
@@ -169,10 +158,11 @@ ORKOrderedTask *task =
let task = ORKOrderedTask(identifier: "task", steps: [myStep])
```
### 4. Present the Task
###4. Present the Task
Create a task view controller (`ORKTaskViewController`) and initialize it with your `task`. A task
view controller manages a task and collects the results of each step. In this case, your task view
Create a task view controller (`ORKTaskViewController`) and initialize
it with your `task`. A task view controller manages a task and collects the
results of each step. In this case, your task view
controller simply displays your instruction step.
*Objective-C*
@@ -192,9 +182,9 @@ taskViewController.delegate = self
presentViewController(taskViewController, animated: true, completion: nil)
```
The above snippet assumes that your class implements the `ORKTaskViewControllerDelegate` protocol.
This has just one required method, which you must implement in order to handle the completion of
the task:
The above snippet assumes that your class implements the
`ORKTaskViewControllerDelegate` protocol. This has just one required method,
which you must implement in order to handle the completion of the task:
*Objective-C*
@@ -226,7 +216,8 @@ func taskViewController(taskViewController: ORKTaskViewController,
```
If you now run your app, you should see your first *ResearchKit framework* instruction step:
If you now run your app, you should see your first ResearchKit framework
instruction step:
<center>
<figure>
@@ -239,18 +230,19 @@ If you now run your app, you should see your first *ResearchKit framework* instr
What else can the ResearchKit framework do?
-----------------------------
The *ResearchKit* [`ORKCatalog`](samples/ORKCatalog) sample app is a good place to start. Find the
project in ResearchKit's [`samples`](samples) directory. This project includes a list of all the
types of steps supported by the *ResearchKit framework* in the first tab, and displays a browser for the
results of the last completed task in the second tab. The third tab shows some examples from the *Charts module*.
The ResearchKit [`ORKCatalog`](samples/ORKCatalog) sample app is a
good place to start. Find the project in ResearchKit's
[`samples`](samples) directory. This project includes a list of all
the types of steps supported by the ResearchKit framework in one tab, and displays a
browser for the results of the last completed task in the other tab.
License<a name="license"></a>
=======
The source in the *ResearchKit* repository is made available under the following license unless
another license is explicitly identified:
The source in the ResearchKit repository is made available under the
following license unless another license is explicitly identified:
```
Copyright (c) 2015, Apple Inc. All rights reserved.
+47 -115
View File
@@ -1,73 +1,5 @@
# ResearchKit Release Notes
## ResearchKit 1.4 Release Notes
*ResearchKit 1.4* supports *iOS* and requires *Xcode 8.0* or newer. The minimum supported *Base SDK* is *8.0*.
In addition to general stabiltiy and performance improvements, *ResearchKit 1.4* includes the following new features and enhancements.
- **New Active Task**
- **Hand Tremor Task**
*Contributed by [Shannon Young](https://github.com/syoung-smallwisdom).*
The *Hand Tremor Task* asks the participant to hold the device with their most affected hand in various positions while accelerometer and motion data is captured.
- **Walk Back and Forth Task**
*Contributed by [Shannon Young](https://github.com/syoung-smallwisdom).*
The *Walk Back and Forth Task* addresses the concern of researchers/participants who have difficulty locating an unobstructed path for 20 steps.
Instructs users to walk and turn in a full circle, allowing the tests to be conducted in a smaller space.
- **New Steps**
- **Video Capture Step**
*Contributed by [Apple Inc](https://github.com/researchkit).*
The *Video Capture Step* provides a step to be used to record video.
The step can be used as part of a survey to capture video respones as well.
- **Review Step**
*Contributed by [Oliver Schäfer](https://github.com/oliverschaefer).*
The *Review Step* allows a participant to review and modify their answers to a survey.
The step can be used in the middle of a survey, at the end of a survey, or a standalone module.
- **Signature Step**
*Contributed by [Oliver Schäfer](https://github.com/oliverschaefer).*
The *Signature Step* provides an interface for a participant to sign their name.
The step can be used for handwriting detection or simply to sign a document.
- **Table Step**
*Contributed by [Shannon Young](https://github.com/syoung-smallwisdom).*
The *Table Step* provides a way to neatly display data in a table.
- **Other Improvements**
- **Data Collection Module**
*Contributed by [Apple Inc](https://github.com/researchkit).*
The *Data Collection Module* makes it even easier to aggregate data from HealthKit and device sensors.
- **Tapping Test**
*Contributed by [Michał Zaborowski](https://github.com/m1entus).*
The *Tapping Test* is updated to include tap duration as part of the result.
## ResearchKit 1.3 Release Notes
@@ -75,88 +7,88 @@ In addition to general stabiltiy and performance improvements, *ResearchKit 1.4*
In addition to general stability and performance improvements, *ResearchKit 1.3* includes the following new features and enhancements.
- **New Active Task**
- **New Active Tasks**
- **9-Hole Peg Test**
*Contributed by [Julien Therier](https://github.com/julientherier).*
The *9-Hole Peg Test task* is used to test upper extremity functionality.
The test involves putting a variable number of pegs in a hole and subsequently removing them.
The *[9-Hole Peg Test] task* is used to test upper extremity functionality.
The test involves putting a variable variable number of pegs in a hole, and then removing them.
The test is documented in the scientific literature to measure the *[MSFC score in Multiple Sclerosis](http://www.nationalmssociety.org/For-Professionals/Researchers/Resources-for-Researchers/Clinical-Study-Measures/9-Hole-Peg-Test-(9-HPT))* or *[Parkinson's Disease](http://www.ncbi.nlm.nih.gov/pubmed/22020457)*.
- **Sample App**
*Contributed by [Apple Inc](https://github.com/researchkit).*
The *Sample App* (`ORKSample` project on *ResearchKit*'s workspace) serves as a template application that combines different modules from the *ResearchKit framework*.
The *[Sample App]* serves as a template application that combines different modules from the ResearchKit framework.
- **Account Module**
*Contributed by [Apple Inc](https://github.com/researchkit).*
The *Account Module* provides steps to facilitate account creation and login.
The *[Account Module]* provides steps to facilitate account creation and login.
The module includes the following steps:
1. *Registration*, used to allow the participant to create a new account.
2. *Verification*, used to confirm if the participant has verified the provided email address.
3. *Login*, used to allow registered users to login.
1. Registration to create a new account.
2. Verification to verify email.
3. Login to allow registered users to login.
- **Passcode with Touch ID**
*Contributed by [Apple Inc](https://github.com/researchkit).*
The *Passcode with Touch ID module* provides the ability to secure any *ResearchKit* application with a numeric passcode.
This module includes a *Keychain Wrapper* that stores the passcode on the device, as well as the option to use *Touch ID* on compatible devices. The passcode module supports 4-digit and 6-digit numeric codes.
The passcode module provides the following components:
1. *Passcode creation step*, which can be used as part of onboarding to create a passcode and store it in the keychain.
2. *Passcode authentication view controller*, which can be modally presented when appropriate.
3. *Passcode modification view controller*, which allows the participant to change their passcode.
The *[Passcode with Touch ID] module* provides the ability to secure any ResearchKit application with a pin entry.
This module includes a *Keychain Wrapper* that stores the passcode on the device, as well as the option to use Touch ID on compatible devices. The passcode module supports 4-pin and 6-pin entries.
The passcode module can be used in the following scenarios:
1. Passcode creation step which can be used as part of onboarding to create a passcode and store it in the keychain.
2. Passcode authentication view controller which can be presented modally when appropriate.
3. Passcode modification view controller which allows the participant to change their passcode.
- **Other Improvements**
- **Optional Form Items**
*Contributed by [Ricardo Sánchez-Sáez](https://github.com/rsanchezsaez).*
Adds the `optional` property to `ORKFormItem`.
The *Continue/Done* button of form steps is enabled when all of the following conditions are met:
- At least one form item has an answer.
- All the non-optional form items have answers.
- All answered form items have valid answers.
Implements the `ORKFormItem` `optional` property.
The *Continue/Done* button of form steps enables only if:
- At least one form item has an answer.
- All answered form items are valid.
- All the non-optional form items have answers.
- **Location Question**
*Contributed by [Quintiles](https://github.com/QuintilesRK).*
A *Location Question* can be used to request details about the participant's current location or about a specific address.
The question uses *MapKit* to provide a visual representation for the specified address.
A *Location Question* can be used to request details about the participant's current location or a specific address.
The question uses *MapKit* to provides a visual representation for the specified address.
- **Wait Step**
*Contributed by [Quintiles](https://github.com/QuintilesRK).*
The *Wait Step* provides a step to be used in-between steps when additional data processing is required.
The step supports both indeterminate and determinate progress views, as well as the ability to show text status updates.
- **Validated Text Answer Format**
*Contributed by [Quintiles](https://github.com/QuintilesRK).*
The *Validated Text Answer Format* enhances the existing *Text Answer Format* by providing input validation using a regular expression.
A valid *NSRegularExpression* object and an *error message* string are required to properly use this answer format.
## ResearchKit 1.2 Release Notes
@@ -238,7 +170,7 @@ In addition to general stability and performance improvements, *ResearchKit 1.1*
A new type of *conditional ordered task* (`ORKNavigableOrderedTask`) has been implemented.
The developer can use the `ORKStepNavigationRule` subclasses to dynamically navigate between the task steps:
- `ORKPredicateStepNavigationRule` allows to make conditional jumps by matching previous results (either those of the ongoing task, or those of any previously stored task result tree). You typically use the class methods in the `ORKResultPredicate` class to match answers in the most commonly used result types.
- `ORKPredicateStepNavigationRule` allows to make conditional jumps by matching previous results (either those of the the ongoing task, or those of any previously stored task result tree). You typically use the class methods in the `ORKResultPredicate` class to match answers in the most commonly used result types.
- `ORKDirectStepNavigationRule` provides support for unconditional jumps.
- **New Active Tasks**
@@ -284,4 +216,4 @@ In addition to general stability and performance improvements, *ResearchKit 1.1*
*Contributed by [Apple Inc.](https://github.com/researchkit) and [Ricardo Sánchez-Sáez](https://github.com/rsanchezsaez).*
*iPhone landscape orientation support* has been implemented.
*iPhone landscape orientation support* has been implemented.
+1 -1
View File
@@ -8,7 +8,7 @@ Pod::Spec.new do |s|
s.author = { 'researchkit.org' => 'http://researchkit.org' }
s.source = { :git => 'https://github.com/ResearchKit/ResearchKit.git', :tag => s.version.to_s }
s.public_header_files = `./scripts/find_headers.rb --public --private`.split("\n")
s.source_files = 'ResearchKit/**/*.{h,m,swift}'
s.source_files = 'ResearchKit/**/*.{h,m}'
s.resources = 'ResearchKit/**/*.{fsh,vsh}', 'ResearchKit/Animations/**/*.m4v', 'ResearchKit/Artwork.xcassets', 'ResearchKit/Localized/*.lproj'
s.platform = :ios, '8.0'
s.requires_arc = true
File diff suppressed because it is too large Load Diff
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0800"
LastUpgradeVersion = "0700"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0800"
LastUpgradeVersion = "0700"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
+1 -1
View File
@@ -30,6 +30,6 @@
// Shared header for accessibility functionality.
#import "UIView+ORKAccessibility.h"
#import "ORKAccessibilityFunctions.h"
#import "ORKLineGraphAccessibilityElement.h"
#import "UIView+ORKAccessibility.h"
@@ -30,11 +30,9 @@
#import "ORKDefines.h"
#import "ORKHelpers_Internal.h"
#import "ORKHelpers.h"
NS_ASSUME_NONNULL_BEGIN
@class ORKScaleSlider;
// Used to properly format values from the ORKScaleSlider.
@@ -45,7 +43,7 @@ ORK_EXTERN NSString *ORKAccessibilityFormatContinuousScaleSliderValue(CGFloat va
ORK_EXTERN void ORKAccessibilityPerformBlockAfterDelay(NSTimeInterval delay, void(^block)(void));
// Convenience for posting an accessibility notification after a delay.
ORK_INLINE void ORKAccessibilityPostNotificationAfterDelay(UIAccessibilityNotifications notification, _Nullable id argument, NSTimeInterval delay) {
ORK_INLINE void ORKAccessibilityPostNotificationAfterDelay(UIAccessibilityNotifications notification, id argument, NSTimeInterval delay) {
ORKAccessibilityPerformBlockAfterDelay(delay, ^{
UIAccessibilityPostNotification(notification, argument);
});
@@ -54,5 +52,3 @@ ORK_INLINE void ORKAccessibilityPostNotificationAfterDelay(UIAccessibilityNotifi
// Creates a string suitable for Voice Over by joining the variables with ", " and avoiding nil and empty strings.
#define ORKAccessibilityStringForVariables(...) _ORKAccessibilityStringForVariables(ORK_NARG(__VA_ARGS__), ##__VA_ARGS__)
ORK_EXTERN NSString *_ORKAccessibilityStringForVariables(NSInteger numParameters, NSString *baseString, ...);
NS_ASSUME_NONNULL_END
@@ -29,14 +29,11 @@
*/
@import UIKit;
#import <UIKit/UIKit.h>
#import "ORKAccessibilityFunctions.h"
#import "ORKAnswerFormat_Internal.h"
#import "ORKScaleSlider.h"
#import "ORKScaleSliderView.h"
#import "ORKAnswerFormat_Internal.h"
#import "ORKAccessibilityFunctions.h"
#import "UIView+ORKAccessibility.h"
@@ -28,16 +28,10 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@import UIKit;
NS_ASSUME_NONNULL_BEGIN
#import <UIKit/UIKit.h>
@interface ORKLineGraphAccessibilityElement : UIAccessibilityElement
- (nonnull instancetype)initWithAccessibilityContainer:(nonnull UIView *)container index:(NSInteger)index maxIndex:(NSInteger)maxIndex;
@end
NS_ASSUME_NONNULL_END
@@ -30,15 +30,11 @@
#import "ORKLineGraphAccessibilityElement.h"
@interface ORKLineGraphAccessibilityElement()
@property (assign, nonatomic) NSInteger index;
@property (assign, nonatomic) NSInteger maxIndex;
@end
@implementation ORKLineGraphAccessibilityElement
- (nonnull instancetype)initWithAccessibilityContainer:(nonnull UIView *)container index:(NSInteger)index maxIndex:(NSInteger)maxIndex {
@@ -29,7 +29,8 @@
*/
@import UIKit;
#import <UIKit/UIKit.h>
#import <ResearchKit/ResearchKit.h>
NS_ASSUME_NONNULL_BEGIN
@@ -29,7 +29,8 @@
*/
@import CoreLocation;
#import <CoreLocation/CoreLocation.h>
#import <ResearchKit/ResearchKit.h>
NS_ASSUME_NONNULL_BEGIN
@@ -30,8 +30,7 @@
#import "CLLocation+ORKJSONDictionary.h"
#import "ORKHelpers_Internal.h"
#import "ORKHelpers.h"
@implementation CLLocation (ORKJSONDictionary)
@@ -46,11 +45,10 @@
NSDate *timestamp = self.timestamp;
CLFloor *floor = self.floor;
NSMutableDictionary *dictionary = [@{@"timestamp": ORKStringFromDateISO8601(timestamp)} mutableCopy];
NSMutableDictionary *dictionary = [@{@"timestamp" : ORKStringFromDateISO8601(timestamp)} mutableCopy];
if (horizAccuracy >= 0) {
dictionary[@"coordinate"] = @{ @"latitude": [NSDecimalNumber numberWithDouble:coord.latitude],
@"longitude": [NSDecimalNumber numberWithDouble:coord.longitude]};
dictionary[@"coordinate"] = @{ @"latitude" : [NSDecimalNumber numberWithDouble:coord.latitude], @"longitude" : [NSDecimalNumber numberWithDouble:coord.longitude]};
dictionary[@"horizontalAccuracy"] = [NSDecimalNumber numberWithDouble:horizAccuracy];
}
if (vertAccuracy >= 0) {
@@ -29,7 +29,8 @@
*/
@import CoreMotion;
#import <CoreMotion/CoreMotion.h>
#import <ResearchKit/ResearchKit.h>
NS_ASSUME_NONNULL_BEGIN
@@ -36,9 +36,9 @@
- (NSDictionary *)ork_JSONDictionary {
NSDictionary *dictionary = @{@"timestamp": [NSDecimalNumber numberWithDouble:self.timestamp],
@"x": [NSDecimalNumber numberWithDouble:self.acceleration.x],
@"y": [NSDecimalNumber numberWithDouble:self.acceleration.y],
@"z": [NSDecimalNumber numberWithDouble:self.acceleration.z]
@"x" : [NSDecimalNumber numberWithDouble:self.acceleration.x],
@"y" : [NSDecimalNumber numberWithDouble:self.acceleration.y],
@"z" : [NSDecimalNumber numberWithDouble:self.acceleration.z]
};
return dictionary;
}
@@ -29,7 +29,8 @@
*/
@import CoreMotion;
#import <CoreMotion/CoreMotion.h>
#import <ResearchKit/ResearchKit.h>
NS_ASSUME_NONNULL_BEGIN
@@ -42,34 +42,34 @@
CMCalibratedMagneticField field = self.magneticField;
NSDictionary *dictionary = @{@"timestamp": [NSDecimalNumber numberWithDouble:self.timestamp],
@"attitude": @{
@"x": [NSDecimalNumber numberWithDouble:attitude.x],
@"y": [NSDecimalNumber numberWithDouble:attitude.y],
@"z": [NSDecimalNumber numberWithDouble:attitude.z],
@"w": [NSDecimalNumber numberWithDouble:attitude.w]
},
@"rotationRate": @{
@"x": [NSDecimalNumber numberWithDouble:rotationRate.x],
@"y": [NSDecimalNumber numberWithDouble:rotationRate.y],
@"z": [NSDecimalNumber numberWithDouble:rotationRate.z]
},
@"gravity": @{
@"x": [NSDecimalNumber numberWithDouble:gravity.x],
@"y": [NSDecimalNumber numberWithDouble:gravity.y],
@"z": [NSDecimalNumber numberWithDouble:gravity.z]
},
@"userAcceleration": @{
@"x": [NSDecimalNumber numberWithDouble:userAccel.x],
@"y": [NSDecimalNumber numberWithDouble:userAccel.y],
@"z": [NSDecimalNumber numberWithDouble:userAccel.z]
},
@"magneticField": @{
@"x": [NSDecimalNumber numberWithDouble:field.field.x],
@"y": [NSDecimalNumber numberWithDouble:field.field.y],
@"z": [NSDecimalNumber numberWithDouble:field.field.z],
@"accuracy": [NSDecimalNumber numberWithDouble:field.accuracy]
}
};
@"attitude" : @{
@"x" : [NSDecimalNumber numberWithDouble:attitude.x],
@"y" : [NSDecimalNumber numberWithDouble:attitude.y],
@"z" : [NSDecimalNumber numberWithDouble:attitude.z],
@"w" : [NSDecimalNumber numberWithDouble:attitude.w]
},
@"rotationRate" : @{
@"x" : [NSDecimalNumber numberWithDouble:rotationRate.x],
@"y" : [NSDecimalNumber numberWithDouble:rotationRate.y],
@"z" : [NSDecimalNumber numberWithDouble:rotationRate.z]
},
@"gravity" : @{
@"x" : [NSDecimalNumber numberWithDouble:gravity.x],
@"y" : [NSDecimalNumber numberWithDouble:gravity.y],
@"z" : [NSDecimalNumber numberWithDouble:gravity.z]
},
@"userAcceleration" : @{
@"x" : [NSDecimalNumber numberWithDouble:userAccel.x],
@"y" : [NSDecimalNumber numberWithDouble:userAccel.y],
@"z" : [NSDecimalNumber numberWithDouble:userAccel.z]
},
@"magneticField" : @{
@"x" : [NSDecimalNumber numberWithDouble:field.field.x],
@"y" : [NSDecimalNumber numberWithDouble:field.field.y],
@"z" : [NSDecimalNumber numberWithDouble:field.field.z],
@"accuracy" : [NSDecimalNumber numberWithDouble:field.accuracy]
}
};
return dictionary;
}
@@ -29,7 +29,8 @@
*/
@import CoreMotion;
#import <CoreMotion/CoreMotion.h>
#import <ResearchKit/ResearchKit.h>
NS_ASSUME_NONNULL_BEGIN
@@ -30,8 +30,7 @@
#import "CMMotionActivity+ORKJSONDictionary.h"
#import "ORKHelpers_Internal.h"
#import "ORKHelpers.h"
static NSString *const ActivityUnknown = @"unknown";
@@ -43,9 +42,9 @@ static NSString *const StartDateKey = @"startDate";
static NSString *const EndDateKey = @"endDate";
static NSString *stringFromActivityConfidence(CMMotionActivityConfidence confidence) {
NSDictionary *confidences = @{@(CMMotionActivityConfidenceHigh): @"high",
@(CMMotionActivityConfidenceMedium): @"medium",
@(CMMotionActivityConfidenceLow): @"low"};
NSDictionary *confidences = @{@(CMMotionActivityConfidenceHigh) : @"high",
@(CMMotionActivityConfidenceMedium) : @"medium",
@(CMMotionActivityConfidenceLow) : @"low"};
return confidences[@(confidence)];
}
@@ -75,9 +74,9 @@ static NSString *const ConfidenceKey = @"confidence";
@implementation CMMotionActivity (ORKJSONDictionary)
- (NSDictionary *)ork_JSONDictionary {
return @{ConfidenceKey: stringFromActivityConfidence(self.confidence),
ActivityKey: activityArray(self),
StartDateKey: ORKStringFromDateISO8601(self.startDate)};
return @{ConfidenceKey : stringFromActivityConfidence(self.confidence),
ActivityKey : activityArray(self),
StartDateKey : ORKStringFromDateISO8601(self.startDate)};
}
@end
@@ -29,7 +29,8 @@
*/
@import CoreMotion;
#import <CoreMotion/CoreMotion.h>
#import <ResearchKit/ResearchKit.h>
NS_ASSUME_NONNULL_BEGIN
@@ -30,10 +30,8 @@
#import "CMPedometerData+ORKJSONDictionary.h"
#import "ORKHelpers_Internal.h"
@import CoreMotion;
#import "ORKHelpers.h"
#import <CoreMotion/CoreMotion.h>
@implementation CMPedometerData (ORKJSONDictionary)
@@ -29,7 +29,8 @@
*/
@import HealthKit;
#import <HealthKit/HealthKit.h>
#import <ResearchKit/ResearchKit.h>
NS_ASSUME_NONNULL_BEGIN
@@ -30,8 +30,7 @@
#import "HKSample+ORKJSONDictionary.h"
#import "ORKHelpers_Internal.h"
#import "ORKHelpers.h"
static NSString *const HKSampleIdentifierKey = @"type"; // For compatibility with Health XML export
@@ -90,7 +89,7 @@ static NSString *const HKCorrelatedObjectsKey = @"objects";
}
if (options & ORKSampleIncludeSource) {
HKSource *source = [[self sourceRevision] source];
HKSource *source = [self source];
if (source.name) {
mutableDictionary[HKSourceKey] = source.name;
}
@@ -29,7 +29,6 @@
*/
@import UIKit;
#import <ResearchKit/ORKRecorder.h>
@@ -30,15 +30,12 @@
#import "ORKAccelerometerRecorder.h"
#import "ORKDataLogger.h"
#import "ORKRecorder_Internal.h"
#import "ORKHelpers_Internal.h"
#import "CMAccelerometerData+ORKJSONDictionary.h"
@import CoreMotion;
#import <CoreMotion/CoreMotion.h>
#import "ORKRecorder_Internal.h"
#import "ORKRecorder_Private.h"
#import "ORKHelpers.h"
@interface ORKAccelerometerRecorder () {
@@ -90,10 +87,10 @@
self.motionManager = [self createMotionManager];
if (!_logger) {
NSError *error = nil;
_logger = [self makeJSONDataLoggerWithError:&error];
NSError *err = nil;
_logger = [self makeJSONDataLoggerWithError:&err];
if (!_logger) {
[self finishRecordingWithError:error];
[self finishRecordingWithError:err];
return;
}
}
@@ -101,7 +98,7 @@
if (!self.motionManager || !self.motionManager.accelerometerAvailable) {
NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain
code:NSFeatureUnsupportedError
userInfo:@{@"recorder": self}];
userInfo:@{@"recorder" : self}];
[self finishRecordingWithError:error];
return;
}
@@ -127,7 +124,7 @@
}
- (NSDictionary *)userInfo {
return @{ @"frequency": @(self.frequency) };
return @{ @"frequency" : @(self.frequency) };
}
- (void)stop {
+3 -22
View File
@@ -29,10 +29,10 @@
*/
@import UIKit;
@import HealthKit;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKStep.h>
#import <UIKit/UIKit.h>
#import <HealthKit/HealthKit.h>
@class ORKRecorderConfiguration;
@@ -103,17 +103,6 @@ automatically navigates forward when the timer expires.
*/
@property (nonatomic) BOOL shouldSpeakCountDown;
/**
A Boolean value indicating whether to speak the halfway point in the count down of the
duration of a timed step.
When the value of this property is `YES`, `AVSpeechSynthesizer` is used to synthesize the countdown. Note that this property is ignored if VoiceOver is enabled.
The default value of this property is `NO`.
*/
@property (nonatomic) BOOL shouldSpeakRemainingTimeAtHalfway;
/**
A Boolean value indicating whether to start the count down timer automatically when the step starts, or
require the user to take some explicit action to start the step, such as tapping a button.
@@ -182,14 +171,6 @@ The default value of this property is `NO`.
*/
@property (nonatomic, copy, nullable) NSString *spokenInstruction;
/**
Localized text that represents an instructional voice prompt for when the step finishes.
Instructional speech begins when the step finishes. If VoiceOver is active,
the instruction is spoken by VoiceOver.
*/
@property (nonatomic, copy, nullable) NSString *finishedSpokenInstruction;
/**
An image to be displayed below the instructions for the step.
+3 -16
View File
@@ -30,15 +30,12 @@
#import "ORKActiveStep.h"
#import "ORKHelpers.h"
#import "ORKStep_Private.h"
#import "ORKActiveStep_Internal.h"
#import "ORKActiveStepViewController.h"
#import "ORKRecorder_Private.h"
#import "ORKStep_Private.h"
#import "ORKHelpers_Internal.h"
@implementation ORKActiveStep
@@ -65,9 +62,7 @@
}
- (BOOL)hasVoice {
BOOL hasSpokenInstruction = (_spokenInstruction != nil && _spokenInstruction.length > 0);
BOOL hasFinishedSpokenInstruction = (_finishedSpokenInstruction != nil && _finishedSpokenInstruction.length > 0);
return (hasSpokenInstruction || hasFinishedSpokenInstruction);
return (_spokenInstruction != nil && _spokenInstruction.length > 0);
}
- (BOOL)isRestorable {
@@ -91,7 +86,6 @@
step.stepDuration = self.stepDuration;
step.shouldStartTimerAutomatically = self.shouldStartTimerAutomatically;
step.shouldSpeakCountDown = self.shouldSpeakCountDown;
step.shouldSpeakRemainingTimeAtHalfway = self.shouldSpeakRemainingTimeAtHalfway;
step.shouldShowDefaultTimer = self.shouldShowDefaultTimer;
step.shouldPlaySoundOnStart = self.shouldPlaySoundOnStart;
step.shouldPlaySoundOnFinish = self.shouldPlaySoundOnFinish;
@@ -100,7 +94,6 @@
step.shouldUseNextAsSkipButton = self.shouldUseNextAsSkipButton;
step.shouldContinueOnFinish = self.shouldContinueOnFinish;
step.spokenInstruction = self.spokenInstruction;
step.finishedSpokenInstruction = self.finishedSpokenInstruction;
step.recorderConfigurations = [self.recorderConfigurations copy];
step.image = self.image;
return step;
@@ -112,7 +105,6 @@
ORK_DECODE_DOUBLE(aDecoder, stepDuration);
ORK_DECODE_BOOL(aDecoder, shouldStartTimerAutomatically);
ORK_DECODE_BOOL(aDecoder, shouldSpeakCountDown);
ORK_DECODE_BOOL(aDecoder, shouldSpeakRemainingTimeAtHalfway);
ORK_DECODE_BOOL(aDecoder, shouldShowDefaultTimer);
ORK_DECODE_BOOL(aDecoder, shouldPlaySoundOnStart);
ORK_DECODE_BOOL(aDecoder, shouldPlaySoundOnFinish);
@@ -121,7 +113,6 @@
ORK_DECODE_BOOL(aDecoder, shouldUseNextAsSkipButton);
ORK_DECODE_BOOL(aDecoder, shouldContinueOnFinish);
ORK_DECODE_OBJ_CLASS(aDecoder, spokenInstruction, NSString);
ORK_DECODE_OBJ_CLASS(aDecoder, finishedSpokenInstruction, NSString);
ORK_DECODE_IMAGE(aDecoder, image);
ORK_DECODE_OBJ_ARRAY(aDecoder, recorderConfigurations, ORKRecorderConfiguration);
}
@@ -133,7 +124,6 @@
ORK_ENCODE_DOUBLE(aCoder, stepDuration);
ORK_ENCODE_BOOL(aCoder, shouldStartTimerAutomatically);
ORK_ENCODE_BOOL(aCoder, shouldSpeakCountDown);
ORK_ENCODE_BOOL(aCoder, shouldSpeakRemainingTimeAtHalfway);
ORK_ENCODE_BOOL(aCoder, shouldShowDefaultTimer);
ORK_ENCODE_BOOL(aCoder, shouldPlaySoundOnStart);
ORK_ENCODE_BOOL(aCoder, shouldPlaySoundOnFinish);
@@ -143,7 +133,6 @@
ORK_ENCODE_BOOL(aCoder, shouldContinueOnFinish);
ORK_ENCODE_IMAGE(aCoder, image);
ORK_ENCODE_OBJ(aCoder, spokenInstruction);
ORK_ENCODE_OBJ(aCoder, finishedSpokenInstruction);
ORK_ENCODE_OBJ(aCoder, recorderConfigurations);
}
@@ -153,14 +142,12 @@
__typeof(self) castObject = object;
return (isParentSame &&
ORKEqualObjects(self.spokenInstruction, castObject.spokenInstruction) &&
ORKEqualObjects(self.finishedSpokenInstruction, castObject.finishedSpokenInstruction) &&
ORKEqualObjects(self.recorderConfigurations, castObject.recorderConfigurations) &&
ORKEqualObjects(self.image, castObject.image) &&
(self.stepDuration == castObject.stepDuration) &&
(self.shouldShowDefaultTimer == castObject.shouldShowDefaultTimer) &&
(self.shouldStartTimerAutomatically == castObject.shouldStartTimerAutomatically) &&
(self.shouldSpeakCountDown == castObject.shouldSpeakCountDown) &&
(self.shouldSpeakRemainingTimeAtHalfway == castObject.shouldSpeakRemainingTimeAtHalfway) &&
(self.shouldPlaySoundOnStart == castObject.shouldPlaySoundOnStart) &&
(self.shouldPlaySoundOnFinish == castObject.shouldPlaySoundOnFinish) &&
(self.shouldVibrateOnStart == castObject.shouldVibrateOnStart) &&
@@ -29,7 +29,7 @@
*/
@import UIKit;
#import <ResearchKit/ResearchKit_Private.h>
#import "ORKLabel.h"
@@ -30,12 +30,10 @@
#import "ORKActiveStepQuantityView.h"
#import "ORKSubheadlineLabel.h"
#import "ORKTintedImageView.h"
#import "ORKHelpers_Internal.h"
#import "ORKHelpers.h"
#import "ORKSkin.h"
#import "ORKTintedImageView.h"
#import "ORKSubheadlineLabel.h"
@implementation ORKQuantityLabel
+2 -1
View File
@@ -29,7 +29,8 @@
*/
@import Foundation;
#import <Foundation/Foundation.h>
#import <ResearchKit/ResearchKit.h>
NS_ASSUME_NONNULL_BEGIN
+3 -6
View File
@@ -30,12 +30,9 @@
#import "ORKActiveStepTimer.h"
#import "ORKHelpers_Internal.h"
@import UIKit;
#include <mach/mach.h>
#include <mach/mach_time.h>
#import <UIKit/UIKit.h>
static NSTimeInterval timeIntervalFromMachTime(uint64_t delta) {
@@ -200,9 +197,9 @@ static NSTimeInterval timeIntervalFromMachTime(uint64_t delta) {
assert(0);
return;
}
ORKWeakTypeOf(self) weakSelf = self;
__weak typeof(self) weakSelf = self;
dispatch_source_set_event_handler(_timer, ^{
ORKStrongTypeOf(self) strongSelf = weakSelf;
typeof(self) strongSelf = weakSelf;
[strongSelf hiqueue_event];
});
@@ -29,20 +29,18 @@
*/
@import UIKit;
#import <UIKit/UIKit.h>
#import <ResearchKit/ResearchKit_Private.h>
#import "ORKCustomStepView_Internal.h"
#import "ORKCountdownLabel.h"
#import "ORKTextButton.h"
NS_ASSUME_NONNULL_BEGIN
@class ORKActiveStep;
@class ORKCountdownLabel;
@class ORKTextButton;
@interface ORKActiveStepTimerView : ORKActiveStepCustomView
@property (nonatomic, strong, nullable) ORKCountdownLabel *countDownLabel;
@property (nonatomic, strong, nullable) ORKTextButton *startTimerButton;
@property (nonatomic, strong, nullable) ORKActiveStep *step;
@@ -30,22 +30,17 @@
#import "ORKActiveStepTimerView.h"
#import "ORKActiveStepTimer.h"
#import "ORKCountdownLabel.h"
#import "ORKHelpers.h"
#import "ORKSkin.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKVoiceEngine.h"
#import "ORKSurveyAnswerCellForText.h"
#import "ORKSurveyAnswerCellForNumber.h"
#import "ORKTextButton.h"
#import "ORKVoiceEngine.h"
#import "ORKActiveStep_Internal.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKStepViewController_Internal.h"
#import "ORKActiveStep_Internal.h"
#import "ORKHelpers_Internal.h"
#import "ORKSkin.h"
@implementation ORKActiveStepTimerView {
BOOL _started;
@@ -29,7 +29,6 @@
*/
@import UIKit;
#import <ResearchKit/ORKStepViewController.h>
#import <ResearchKit/ORKRecorder.h>
@@ -30,27 +30,23 @@
#import "ORKActiveStepViewController.h"
#import "ORKActiveStepTimer.h"
#import "ORKActiveStepTimerView.h"
#import "ORKActiveStepView.h"
#import "ORKNavigationContainerView.h"
#import "ORKStepHeaderView_Internal.h"
#import "ORKVerticalContainerView.h"
#import "ORKVoiceEngine.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKStepViewController_Internal.h"
#import "ORKTaskViewController_Internal.h"
#import "ORKRecorder_Internal.h"
#import "ORKActiveStep_Internal.h"
#import "ORKResult.h"
#import "ORKTask.h"
#import "ORKAccessibility.h"
#import "ORKHelpers_Internal.h"
#import "ORKSkin.h"
#import "ORKHelpers.h"
#import "ORKActiveStep.h"
#import "ORKTask.h"
#import "ORKTaskViewController.h"
#import "ORKVerticalContainerView.h"
#import "ORKStepViewController_Internal.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKActiveStep_Internal.h"
#import "ORKRecorder_Internal.h"
#import "ORKTaskViewController_Internal.h"
#import "ORKActiveStepTimerView.h"
#import "ORKActiveStepTimer.h"
#import "ORKAccessibility.h"
#import "ORKStepHeaderView_Internal.h"
#import "ORKActiveStepView.h"
@interface ORKActiveStepViewController () {
@@ -61,7 +57,6 @@
SystemSoundID _alertSound;
NSURL *_alertSoundURL;
BOOL _hasSpokenHalfwayCountdown;
}
@property (nonatomic, strong) NSArray *recorders;
@@ -367,9 +362,6 @@
if (self.activeStep.shouldVibrateOnFinish) {
AudioServicesPlayAlertSound(kSystemSoundID_Vibrate);
}
if (self.activeStep.hasVoice && self.activeStep.finishedSpokenInstruction) {
[[ORKVoiceEngine sharedVoiceEngine] speakText:self.activeStep.finishedSpokenInstruction];
}
if (!self.activeStep.startsFinished) {
if (self.activeStep.shouldContinueOnFinish) {
[self goForward];
@@ -398,12 +390,12 @@
NSTimeInterval stepDuration = self.activeStep.stepDuration;
if (stepDuration > 0) {
ORKWeakTypeOf(self) weakSelf = self;
__weak typeof(self) weakSelf = self;
_activeStepTimer = [[ORKActiveStepTimer alloc] initWithDuration:stepDuration
interval:_timerUpdateInterval
runtime:0
handler:^(ORKActiveStepTimer *timer, BOOL finished) {
ORKStrongTypeOf(self) strongSelf = weakSelf;
typeof(self) strongSelf = weakSelf;
[strongSelf countDownTimerFired:timer finished:finished];
}];
[_activeStepTimer resume];
@@ -418,7 +410,6 @@
ORKActiveStepCustomView *customView = _activeStepView.activeCustomView;
[customView updateDisplay:self];
ORKVoiceEngine *voice = [ORKVoiceEngine sharedVoiceEngine];
if (!finished && self.activeStep.shouldSpeakCountDown) {
@@ -432,13 +423,6 @@
[voice speakInt:countDownValue];
}
}
BOOL isHalfway = !_hasSpokenHalfwayCountdown && timer.runtime > timer.duration / 2.0;
if (!finished && self.activeStep.shouldSpeakRemainingTimeAtHalfway && !UIAccessibilityIsVoiceOverRunning() && isHalfway) {
_hasSpokenHalfwayCountdown = YES;
NSString *text = [NSString stringWithFormat:ORKLocalizedString(@"COUNTDOWN_SPOKEN_REMAINING_%@", nil), @(countDownValue)];
[voice speakText:text];
}
}
- (BOOL)timerActive {
@@ -466,7 +450,7 @@
- (void)recorder:(ORKRecorder *)recorder didFailWithError:(NSError *)error {
if (error) {
ORKStrongTypeOf(self.delegate) strongDelegate = self.delegate;
STRONGTYPE(self.delegate) strongDelegate = self.delegate;
if ([strongDelegate respondsToSelector:@selector(stepViewController:recorder:didFailWithError:)]) {
[strongDelegate stepViewController:self recorder:recorder didFailWithError:error];
}
@@ -30,11 +30,11 @@
#import "ORKActiveStepViewController.h"
#import "ORKActiveStepTimer.h"
NS_ASSUME_NONNULL_BEGIN
@class ORKActiveStepTimer;
@class ORKActiveStepView;
@interface ORKActiveStepViewController ()
@@ -29,14 +29,14 @@
*/
#import "ORKActiveStep.h"
#import <ResearchKit/ORKActiveStep.h>
NS_ASSUME_NONNULL_BEGIN
@interface ORKActiveStep ()
// Convenience methods.
/**
Convenience methods.
*/
- (BOOL)startsFinished;
- (BOOL)hasCountDown;
- (BOOL)hasTitle;
@@ -44,5 +44,3 @@ NS_ASSUME_NONNULL_BEGIN
- (BOOL)hasVoice;
@end
NS_ASSUME_NONNULL_END
@@ -29,7 +29,7 @@
*/
@import UIKit;
#import <UIKit/UIKit.h>
#import "ORKCustomStepView_Internal.h"
+12 -15
View File
@@ -30,13 +30,11 @@
#import "ORKAudioContentView.h"
#import "ORKHeadlineLabel.h"
#import "ORKLabel.h"
#import "ORKAccessibility.h"
#import "ORKHelpers_Internal.h"
#import "ORKHelpers.h"
#import "ORKSkin.h"
#import "ORKLabel.h"
#import "ORKHeadlineLabel.h"
#import "ORKAccessibility.h"
// The central blue region.
@@ -330,16 +328,17 @@ static const CGFloat ValueLineMargin = 1.5;
}
- (void)updateTimerLabel {
static NSDateComponentsFormatter *formatter = nil;
static NSDateComponentsFormatter *_formatter = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSDateComponentsFormatter *formatter = [NSDateComponentsFormatter new];
formatter.unitsStyle = NSDateComponentsFormatterUnitsStylePositional;
formatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorPad;
formatter.allowedUnits = NSCalendarUnitMinute | NSCalendarUnitSecond;
_formatter = formatter;
});
NSString *string = [formatter stringFromTimeInterval:MAX(round(_timeLeft),0)];
NSString *string = [_formatter stringFromTimeInterval:MAX(round(_timeLeft),0)];
_timerLabel.text = string;
_timerLabel.hidden = (string == nil);
}
@@ -352,10 +351,6 @@ static const CGFloat ValueLineMargin = 1.5;
- (void)updateAlertLabelHidden {
NSNumber *sample = _samples.lastObject;
BOOL show = (!_finished && (sample.doubleValue > _alertThreshold)) || _failed;
if (_alertLabel.hidden && show) {
UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, _alertLabel.text);
}
_alertLabel.hidden = !show;
}
@@ -389,9 +384,11 @@ static const CGFloat ValueLineMargin = 1.5;
}
- (NSString *)accessibilityLabel {
NSString *timerAxString = _timerLabel.isHidden ? nil : _timerLabel.accessibilityLabel;
NSString *alertAxString = _alertLabel.isHidden ? nil : _alertLabel.accessibilityLabel;
return ORKAccessibilityStringForVariables(ORKLocalizedString(@"AX_AUDIO_BAR_GRAPH", nil), timerAxString, alertAxString);
if (_alertLabel.isHidden) {
return _timerLabel.accessibilityLabel;
}
return ORKAccessibilityStringForVariables(_timerLabel.accessibilityLabel, _alertLabel.accessibilityLabel);
}
- (UIAccessibilityTraits)accessibilityTraits {
+2 -5
View File
@@ -49,11 +49,8 @@
3. This notice may not be removed or altered from any source distribution.
*/
@import UIKit;
@import AVFoundation;
#import "ORKTypes.h"
#import <ResearchKit/ORKRecorder.h>
#import <AVFoundation/AVFoundation.h>
NS_ASSUME_NONNULL_BEGIN
+17 -17
View File
@@ -49,15 +49,15 @@
3. This notice may not be removed or altered from any source distribution.
*/
#import "ORKAudioGenerator.h"
@import AudioToolbox;
@interface ORKAudioGenerator () {
@public
@public
AudioComponentInstance _toneUnit;
@public
double _frequency;
double _theta;
ORKAudioChannel _activeChannel;
@@ -148,15 +148,15 @@ OSStatus ORKAudioGeneratorRenderTone(void *inRefCon,
- (void)applicationDidBecomeActive:(NSNotification *)notification {
if (_toneUnit) {
__unused OSErr error = AudioOutputUnitStart(_toneUnit);
NSAssert1(error == noErr, @"Error starting unit: %hd", error);
__unused OSErr err = AudioOutputUnitStart(_toneUnit);
NSAssert1(err == noErr, @"Error starting unit: %hd", err);
}
}
- (void)applicationWillResignActive:(NSNotification *)notification {
if (_toneUnit) {
__unused OSErr error = AudioOutputUnitStop(_toneUnit);
NSAssert1(error == noErr, @"Error stopping unit: %hd", error);
__unused OSErr err = AudioOutputUnitStop(_toneUnit);
NSAssert1(err == noErr, @"Error stopping unit: %hd", err);
}
}
@@ -194,12 +194,12 @@ OSStatus ORKAudioGeneratorRenderTone(void *inRefCon,
[self createToneUnit];
// Stop changing parameters on the unit
OSErr error = AudioUnitInitialize(_toneUnit);
NSAssert1(error == noErr, @"Error initializing unit: %hd", error);
OSErr err = AudioUnitInitialize(_toneUnit);
NSAssert1(err == noErr, @"Error initializing unit: %hd", err);
// Start playback
error = AudioOutputUnitStart(_toneUnit);
NSAssert1(error == noErr, @"Error starting unit: %hd", error);
err = AudioOutputUnitStart(_toneUnit);
NSAssert1(err == noErr, @"Error starting unit: %hd", err);
}
}
@@ -240,20 +240,20 @@ OSStatus ORKAudioGeneratorRenderTone(void *inRefCon,
NSAssert(defaultOutput, @"Can't find default output");
// Create a new unit based on this that we'll use for output
OSErr error = AudioComponentInstanceNew(defaultOutput, &_toneUnit);
NSAssert1(_toneUnit, @"Error creating unit: %hd", error);
OSErr err = AudioComponentInstanceNew(defaultOutput, &_toneUnit);
NSAssert1(_toneUnit, @"Error creating unit: %hd", err);
// Set our tone rendering function on the unit
AURenderCallbackStruct input;
input.inputProc = ORKAudioGeneratorRenderTone;
input.inputProcRefCon = (__bridge void *)(self);
error = AudioUnitSetProperty(_toneUnit,
err = AudioUnitSetProperty(_toneUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
0,
&input,
sizeof(input));
NSAssert1(error == noErr, @"Error setting callback: %hd", error);
NSAssert1(err == noErr, @"Error setting callback: %hd", err);
// Set the format to 32 bit, single channel, floating point, linear PCM
const int four_bytes_per_float = 4;
@@ -267,13 +267,13 @@ OSStatus ORKAudioGeneratorRenderTone(void *inRefCon,
streamFormat.mBytesPerFrame = four_bytes_per_float;
streamFormat.mChannelsPerFrame = 2;
streamFormat.mBitsPerChannel = four_bytes_per_float * eight_bits_per_byte;
error = AudioUnitSetProperty (_toneUnit,
err = AudioUnitSetProperty (_toneUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0,
&streamFormat,
sizeof(AudioStreamBasicDescription));
NSAssert1(error == noErr, @"Error setting stream format: %hd", error);
NSAssert1(err == noErr, @"Error setting stream format: %hd", err);
}
- (void)handleInterruption:(id)sender {
@@ -1,68 +0,0 @@
/*
Copyright (c) 2016, Sage Bionetworks
Copyright (c) 2016, Apple Inc.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <ResearchKit/ORKStepNavigationRule.h>
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKAudioLevelNavigationRule : ORKStepNavigationRule
/**
Returns an initialized direct-step navigation rule using the specified destination step identifier.
@param audioLevelStepIdentifier The identifier of the step with the audio file to check.
@param destinationStepIdentifier The identifier of the destination step if audio test passes.
@param recordingSettings Use key AVNumberOfChannelsKey to sepcify the number of recording channels.
@return A audio level step navigation rule.
*/
- (instancetype)initWithAudioLevelStepIdentifier:(NSString *)audioLevelStepIdentifier
destinationStepIdentifier:(NSString *)destinationStepIdentifier
recordingSettings:(NSDictionary *)recordingSettings NS_DESIGNATED_INITIALIZER;
/**
Returns a new direct-step navigation rule initialized from data in a given unarchiver.
@param aDecoder The coder from which to initialize the step navigation rule.
@return A new direct-step navigation rule.
*/
- (instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;
@property (nonatomic, copy, readonly) NSString *audioLevelStepIdentifier;
@property (nonatomic, copy, readonly) NSString *destinationStepIdentifier;
@property (nonatomic, copy, readonly) NSDictionary *recordingSettings;
@end
NS_ASSUME_NONNULL_END
@@ -1,209 +0,0 @@
/*
Copyright (c) 2016, Sage Bionetworks
Copyright (c) 2016, Apple Inc.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKAudioLevelNavigationRule.h"
#import "ORKResult.h"
#import "ORKResultPredicate.h"
#import "ORKStepNavigationRule_Internal.h"
#import "ORKHelpers_Internal.h"
#import <AVFoundation/AVFoundation.h>
Float32 const VolumeThreshold = 0.45;
UInt16 const LinearPCMBitDepth = 16;
Float32 const MaxAmplitude = 32767.0;
Float32 const VolumeClamp = 60.0;
@interface ORKAudioLevelNavigationRule ()
@property (nonatomic, copy, readwrite) NSString *audioLevelStepIdentifier;
@property (nonatomic, copy, readwrite) NSString *destinationStepIdentifier;
@property (nonatomic, copy, readwrite) NSDictionary *recordingSettings;
@end
@implementation ORKAudioLevelNavigationRule
- (instancetype)initWithAudioLevelStepIdentifier:(NSString *)audioLevelStepIdentifier
destinationStepIdentifier:(NSString *)destinationStepIdentifier
recordingSettings:(NSDictionary *)recordingSettings
{
ORKThrowInvalidArgumentExceptionIfNil(audioLevelStepIdentifier);
ORKThrowInvalidArgumentExceptionIfNil(destinationStepIdentifier);
ORKThrowInvalidArgumentExceptionIfNil(recordingSettings);
self = [super init_ork];
if (self) {
_audioLevelStepIdentifier = [audioLevelStepIdentifier copy];
_destinationStepIdentifier = [destinationStepIdentifier copy];
_recordingSettings = [recordingSettings copy];
}
return self;
}
#pragma mark NSSecureCoding
+ (BOOL)supportsSecureCoding {
return YES;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
ORK_DECODE_OBJ_CLASS(aDecoder, audioLevelStepIdentifier, NSString);
ORK_DECODE_OBJ_CLASS(aDecoder, destinationStepIdentifier, NSString);
ORK_DECODE_OBJ_CLASS(aDecoder, recordingSettings, NSDictionary);
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[super encodeWithCoder:aCoder];
ORK_ENCODE_OBJ(aCoder, audioLevelStepIdentifier);
ORK_ENCODE_OBJ(aCoder, destinationStepIdentifier);
ORK_ENCODE_OBJ(aCoder, recordingSettings);
}
#pragma mark NSCopying
- (instancetype)copyWithZone:(NSZone *)zone {
typeof(self) rule = [[[self class] allocWithZone:zone] initWithAudioLevelStepIdentifier:self.audioLevelStepIdentifier destinationStepIdentifier:self.destinationStepIdentifier recordingSettings:self.recordingSettings];
return rule;
}
- (BOOL)isEqual:(id)object {
BOOL isParentSame = [super isEqual:object];
__typeof(self) castObject = object;
return (isParentSame
&& ORKEqualObjects(self.audioLevelStepIdentifier, castObject.audioLevelStepIdentifier)
&& ORKEqualObjects(self.destinationStepIdentifier, castObject.destinationStepIdentifier)
&& ORKEqualObjects(self.recordingSettings, castObject.recordingSettings));
}
- (NSUInteger)hash {
return _audioLevelStepIdentifier.hash ^ _destinationStepIdentifier.hash ^ _recordingSettings.hash;
}
#pragma mark - Required overrides
- (NSString *)identifierForDestinationStepWithTaskResult:(ORKTaskResult *)taskResult {
// Get the result file
ORKStepResult *stepResult = (ORKStepResult *)[taskResult resultForIdentifier:self.audioLevelStepIdentifier];
ORKFileResult *audioLevelResult = (ORKFileResult *)[stepResult.results firstObject];
// Check the volume
if ((audioLevelResult.fileURL != nil) && [self checkAudioLevelFromSoundFile:audioLevelResult.fileURL]) {
// Returning nil will drop through to the next step (which should be the the step that has the instructions
// for moving to a quieter room).
return nil;
}
return self.destinationStepIdentifier;
}
- (BOOL)checkAudioLevelFromSoundFile:(NSURL *)fileURL {
// Setup reader
AVURLAsset *urlAsset = [AVURLAsset URLAssetWithURL:fileURL options:nil];
if (urlAsset.tracks.count == 0) {
NSLog(@"No tracks found for urlAsset: %@", fileURL);
return NO;
}
NSError *error = nil;
AVAssetReader *reader = [[AVAssetReader alloc] initWithAsset:urlAsset error:&error];
AVAssetTrack *track = [urlAsset.tracks objectAtIndex:0];
NSDictionary *outputSettings = @{AVFormatIDKey: @(kAudioFormatLinearPCM),
AVLinearPCMBitDepthKey: @(LinearPCMBitDepth),
AVLinearPCMIsBigEndianKey: @(NO),
AVLinearPCMIsFloatKey: @(NO),
AVLinearPCMIsNonInterleaved: @(NO)};
AVAssetReaderTrackOutput *output = [[AVAssetReaderTrackOutput alloc] initWithTrack:track outputSettings:outputSettings];
[reader addOutput:output];
// Setup initial values - Assume 2 channels if not in recording settings
const UInt32 channelCount = (UInt32)[self.recordingSettings[AVNumberOfChannelsKey] unsignedIntegerValue] ? : 2;
const UInt32 bytesPerSample = 2 * channelCount;
// setup criteria block - Use a high-pass filter and a rolling average of the amplitude
// normalized to be < 1
__block Float32 rollingAvg = 0;
__block UInt64 totalCount = 0;
void (^processVolume)(Float32) = ^(Float32 amplitude) {
if (amplitude != 0) {
Float32 dB = 20 * log10(ABS(amplitude) / MaxAmplitude);
float clampedValue = MAX(dB / VolumeClamp, -1) + 1;
totalCount++;
rollingAvg = (rollingAvg * (totalCount - 1) + clampedValue) / totalCount;
}
};
// While there are samples to read and the number of samples above the decibel threshold
// is less than the total number of allowed samples over the limit, keep going
[reader startReading];
while (reader.status == AVAssetReaderStatusReading) {
AVAssetReaderTrackOutput *trackOutput = (AVAssetReaderTrackOutput *)[reader.outputs objectAtIndex:0];
CMSampleBufferRef sampleBufferRef = [trackOutput copyNextSampleBuffer];
if (sampleBufferRef) {
CMBlockBufferRef blockBufferRef = CMSampleBufferGetDataBuffer(sampleBufferRef);
size_t length = CMBlockBufferGetDataLength(blockBufferRef);
NSMutableData *data = [NSMutableData dataWithLength:length];
CMBlockBufferCopyDataBytes(blockBufferRef, 0, length, data.mutableBytes);
SInt16 *samples = (SInt16 *) data.mutableBytes;
UInt64 sampleCount = length / bytesPerSample;
for (UInt32 i = 0; i < sampleCount ; i++) {
Float32 left = (Float32) *samples++;
processVolume(left);
if (channelCount == 2) {
Float32 right = (Float32) *samples++;
processVolume(right);
}
}
CMSampleBufferInvalidate(sampleBufferRef);
CFRelease(sampleBufferRef);
}
}
return rollingAvg > VolumeThreshold;
}
@end
+1 -2
View File
@@ -29,9 +29,8 @@
*/
@import UIKit;
@import AVFoundation;
#import <ResearchKit/ORKRecorder.h>
#import <AVFoundation/AVFoundation.h>
NS_ASSUME_NONNULL_BEGIN
+6 -20
View File
@@ -30,10 +30,10 @@
#import "ORKAudioRecorder.h"
#import "ORKHelpers.h"
#import "ORKRecorder_Internal.h"
#import "ORKHelpers_Internal.h"
#import "ORKRecorder_Private.h"
#import "ORKDefines_Private.h"
@interface ORKAudioRecorder ()
@@ -42,8 +42,6 @@
@property (nonatomic, copy) NSDictionary *recorderSettings;
@property (nonatomic, copy) NSString *savedSessionCategory;
@end
@@ -81,16 +79,6 @@
return self;
}
- (void)restoreSavedAudioSessionCategory {
if (_savedSessionCategory) {
NSError *error;
if (![[AVAudioSession sharedInstance] setCategory:_savedSessionCategory error:&error]) {
ORK_Log_Error(@"Failed to restore the audio session category: %@", [error localizedDescription]);
}
_savedSessionCategory = nil;
}
}
- (void)start {
if (self.outputDirectory == nil) {
@throw [NSException exceptionWithName:NSDestinationInvalidException reason:@"audioRecorder requires an output directory" userInfo:nil];
@@ -107,7 +95,6 @@
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
_savedSessionCategory = audioSession.category;
if (![audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&error]) {
[self finishRecordingWithError:error];
return;
@@ -204,13 +191,12 @@
[self applyFileProtection:ORKFileProtectionComplete toFileAtURL:[self recordingFileURL]];
#endif
[self restoreSavedAudioSessionCategory];
}
}
- (void)finishRecordingWithError:(NSError *)error {
[self doStopRecording];
[super finishRecordingWithError:error];
}
@@ -245,7 +231,7 @@
return [[self recordingDirectoryURL] URLByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", [self logName], [self extension]]];
}
- (BOOL)recreateFileWithError:(NSError **)error {
- (BOOL)recreateFileWithError:(NSError * __autoreleasing *)error {
NSURL *url = [self recordingFileURL];
if (!url) {
if (error) {
@@ -267,7 +253,7 @@
}
[fileManager createFileAtPath:[url path] contents:nil attributes:nil];
[fileManager setAttributes:@{NSFileProtectionKey: ORKFileProtectionFromMode(ORKFileProtectionCompleteUnlessOpen)} ofItemAtPath:[url path] error:error];
[fileManager setAttributes:@{NSFileProtectionKey : ORKFileProtectionFromMode(ORKFileProtectionCompleteUnlessOpen)} ofItemAtPath:[url path] error:error];
return YES;
}
-1
View File
@@ -29,7 +29,6 @@
*/
@import Foundation;
#import <ResearchKit/ORKActiveStep.h>
+1 -4
View File
@@ -30,13 +30,10 @@
#import "ORKAudioStep.h"
#import "ORKAudioStepViewController.h"
#import "ORKHelpers.h"
#import "ORKStep_Private.h"
#import "ORKHelpers_Internal.h"
@implementation ORKAudioStep
@@ -29,9 +29,7 @@
*/
@import Foundation;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStepViewController.h>
#import <ResearchKit/ResearchKit_Private.h>
NS_ASSUME_NONNULL_BEGIN
@@ -39,8 +37,6 @@ NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKAudioStepViewController : ORKActiveStepViewController
@property (nonatomic, assign) CGFloat alertThreshold;
@end
NS_ASSUME_NONNULL_END
@@ -30,22 +30,17 @@
#import "ORKAudioStepViewController.h"
#import "ORKActiveStepTimer.h"
#import "ORKActiveStepView.h"
#import "ORKAudioContentView.h"
#import "ORKCustomStepView_Internal.h"
#import "ORKVerticalContainerView.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKAudioRecorder.h"
#import "ORKAudioStep.h"
#import "ORKVerticalContainerView.h"
#import <AVFoundation/AVFoundation.h>
#import "ORKActiveStepTimer.h"
#import "ORKHelpers.h"
#import "ORKStep_Private.h"
#import "ORKHelpers_Internal.h"
@import AVFoundation;
#import "ORKAudioStep.h"
#import "ORKAudioRecorder.h"
#import "ORKActiveStepView.h"
#import "ORKCustomStepView_Internal.h"
@interface ORKAudioStepViewController ()
@@ -71,23 +66,11 @@
return self;
}
- (void)setAlertThreshold:(CGFloat)alertThreshold {
_alertThreshold = alertThreshold;
if (self.isViewLoaded && alertThreshold > 0) {
_audioContentView.alertThreshold = alertThreshold;
}
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
_audioContentView = [ORKAudioContentView new];
_audioContentView.timeLeft = self.audioStep.stepDuration;
if (self.alertThreshold > 0) {
_audioContentView.alertThreshold = self.alertThreshold;
}
self.activeStepView.activeCustomView = _audioContentView;
}
@@ -132,9 +115,9 @@
- (void)startNewTimerIfNeeded {
if (!_timer) {
NSTimeInterval duration = self.audioStep.stepDuration;
ORKWeakTypeOf(self) weakSelf = self;
__weak typeof(self) weakSelf = self;
_timer = [[ORKActiveStepTimer alloc] initWithDuration:duration interval:duration / 100 runtime:0 handler:^(ORKActiveStepTimer *timer, BOOL finished) {
ORKStrongTypeOf(self) strongSelf = weakSelf;
typeof(self) strongSelf = weakSelf;
[strongSelf doSample];
if (finished) {
[strongSelf finish];
+1 -6
View File
@@ -29,13 +29,10 @@
*/
@import Foundation;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ResearchKit.h>
#import <ResearchKit/ORKActiveStep.h>
NS_ASSUME_NONNULL_BEGIN
/**
The `ORKCountdownStep` class represents a step that displays a label and a
countdown for a time equal to its duration.
@@ -49,5 +46,3 @@ ORK_CLASS_AVAILABLE
@interface ORKCountdownStep : ORKActiveStep
@end
NS_ASSUME_NONNULL_END
@@ -30,7 +30,6 @@
#import "ORKCountdownStep.h"
#import "ORKCountdownStepViewController.h"
@@ -29,13 +29,9 @@
*/
@import Foundation;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStepViewController.h>
#import <ResearchKit/ResearchKit_Private.h>
NS_ASSUME_NONNULL_BEGIN
/**
The `ORKCountdownStepViewController` class represents the step view controller that corresponds to an `ORKCountdownStep`.
@@ -47,5 +43,3 @@ ORK_CLASS_AVAILABLE
@interface ORKCountdownStepViewController : ORKActiveStepViewController
@end
NS_ASSUME_NONNULL_END
@@ -30,22 +30,17 @@
#import "ORKCountdownStepViewController.h"
#import "ORKActiveStepTimer.h"
#import "ORKActiveStepView.h"
#import "ORKCustomStepView_Internal.h"
#import "ORKActiveStepViewController_internal.h"
#import "ORKVerticalContainerView.h"
#import "ORKStepViewController_Internal.h"
#import "ORKActiveStepTimer.h"
#import "ORKResult.h"
#import "ORKLabel.h"
#import "ORKSubheadlineLabel.h"
#import "ORKVerticalContainerView.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKStepViewController_Internal.h"
#import "ORKActiveStep.h"
#import "ORKResult.h"
#import "ORKHelpers.h"
#import "ORKAccessibility.h"
#import "ORKHelpers_Internal.h"
#import "ORKActiveStepView.h"
@interface ORKCountDownViewLabel : ORKLabel
+21 -51
View File
@@ -29,8 +29,8 @@
*/
@import Foundation;
#import <ResearchKit/ORKTypes.h>
#import <Foundation/Foundation.h>
#import <ResearchKit/ORKDefines.h>
NS_ASSUME_NONNULL_BEGIN
@@ -65,18 +65,6 @@ NS_ASSUME_NONNULL_BEGIN
@end
@protocol ORKDataLoggerExtendedDelegate <ORKDataLoggerDelegate>
@optional
/**
Tells the delegate that the maximum current log file lifetime changed.
@param dataLogger Source of this event.
*/
- (void)dataLoggerThresholdsDidChange:(ORKDataLogger *)dataLogger;
@end
@class ORKLogFormatter;
/**
@@ -113,7 +101,6 @@ ORK_CLASS_AVAILABLE
*/
+ (ORKDataLogger *)JSONDataLoggerWithDirectory:(NSURL *)url logName:(NSString *)logName delegate:(nullable id<ORKDataLoggerDelegate>)delegate;
+ (instancetype)new NS_UNAVAILABLE;
- (instancetype)init NS_UNAVAILABLE;
/**
@@ -179,7 +166,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if the enumeration was successful; otherwise, `NO`.
*/
- (BOOL)enumerateLogs:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError * _Nullable *)error;
- (BOOL)enumerateLogs:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError * __autoreleasing *)error;
/**
Enumerates the URLs of completed log files not yet marked uploaded,
@@ -194,7 +181,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if the enumeration was successful; otherwise, `NO`.
*/
- (BOOL)enumerateLogsNeedingUpload:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError * _Nullable *)error;
- (BOOL)enumerateLogsNeedingUpload:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError * __autoreleasing *)error;
/**
Enumerates the URLs of completed log files not already marked uploaded,
@@ -209,7 +196,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if the enumeration was successful; otherwise, `NO`.
*/
- (BOOL)enumerateLogsAlreadyUploaded:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError * _Nullable *)error;
- (BOOL)enumerateLogsAlreadyUploaded:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError * __autoreleasing *)error;
/**
Appends an object to the log file, which is formatted with `logFormatter`.
@@ -220,12 +207,12 @@ ORK_CLASS_AVAILABLE
log data is made. If an attempt is made to log data and there is no access due
to file protection, the log is immediately rolled over and a new file created.
@param object Should be an object of a class that is accepted by the logFormatter.
@param error Error output, if the append fails.
@param object Should be an object of a class that is accepted by the logFormatter.
@param error Error output, if the append fails.
@return `YES` if appending succeeds; otherwise, `NO`.
*/
- (BOOL)append:(id)object error:(NSError * _Nullable *)error;
- (BOOL)append:(id)object error:(NSError * __autoreleasing *)error;
/**
Appends multiple objects to the log file.
@@ -233,12 +220,12 @@ ORK_CLASS_AVAILABLE
This method formats and appends all the objects at once. Using this method may have efficiency
and atomicity gains for error handling, compared to making multiple calls to `append:error`.
@param objects An array of objects of a class that is accepted by the logFormatter.
@param error Error output, if the append fails.
@param objects An array of objects of a class that is accepted by the logFormatter.
@param error Error output, if the append fails.
@return `YES` if appending succeeds; otherwise, `NO`.
*/
- (BOOL)appendObjects:(NSArray *)objects error:(NSError * _Nullable *)error;
- (BOOL)appendObjects:(NSArray *)objects error:(NSError * _Nullable __autoreleasing *)error;
/**
Checks whether a file has been marked as uploaded.
@@ -264,7 +251,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if adding or removing the attribute succeeded; otherwise, `NO`.
*/
- (BOOL)markFileUploaded:(BOOL)uploaded atURL:(NSURL *)url error:(NSError * _Nullable *)error;
- (BOOL)markFileUploaded:(BOOL)uploaded atURL:(NSURL *)url error:(NSError * _Nullable __autoreleasing *)error;
/**
Removes files if they are marked uploaded.
@@ -278,7 +265,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if removing the files succeeded; otherwise, `NO`.
*/
- (BOOL)removeUploadedFiles:(NSArray<NSURL *> *)fileURLs withError:(NSError * _Nullable *)error;
- (BOOL)removeUploadedFiles:(NSArray<NSURL *> *)fileURLs withError:(NSError * _Nullable __autoreleasing *)error;
/**
Removes all files managed by this logger (files that have the `logName` prefix).
@@ -287,7 +274,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if removing the files succeeded.; otherwise, `NO`.
*/
- (BOOL)removeAllFilesWithError:(NSError * _Nullable *)error;
- (BOOL)removeAllFilesWithError:(NSError *_Nullable __autoreleasing *)error;
@end
@@ -333,7 +320,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if the write succeeds; otherwise, `NO`.
*/
- (BOOL)beginLogWithFileHandle:(NSFileHandle *)fileHandle error:(NSError * _Nullable *)error;
- (BOOL)beginLogWithFileHandle:(NSFileHandle *)fileHandle error:(NSError * _Nullable __autoreleasing *)error;
/**
Appends the specified object to the log file.
@@ -344,7 +331,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if the write succeeds; otherwise, `NO`.
*/
- (BOOL)appendObject:(id)object fileHandle:(NSFileHandle *)fileHandle error:(NSError * _Nullable *)error;
- (BOOL)appendObject:(id)object fileHandle:(NSFileHandle *)fileHandle error:(NSError * _Nullable __autoreleasing *)error;
/**
Appends the specified objects to the log file.
@@ -355,7 +342,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if the write succeeds; otherwise, `NO`.
*/
- (BOOL)appendObjects:(NSArray *)objects fileHandle:(NSFileHandle *)fileHandle error:(NSError * _Nullable *)error;
- (BOOL)appendObjects:(NSArray *)objects fileHandle:(NSFileHandle *)fileHandle error:(NSError * _Nullable __autoreleasing *)error;
@end
@@ -438,7 +425,6 @@ ORK_CLASS_AVAILABLE
ORK_CLASS_AVAILABLE
@interface ORKDataLoggerManager : NSObject <ORKDataLoggerDelegate>
+ (instancetype)new NS_UNAVAILABLE;
- (instancetype)init NS_UNAVAILABLE;
/**
@@ -519,7 +505,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if the enumeration succeeds; otherwise, `NO`.
*/
- (BOOL)enumerateLogsNeedingUpload:(void (^)(ORKDataLogger *dataLogger, NSURL *logFileUrl, BOOL *stop))block error:(NSError * _Nullable *)error;
- (BOOL)enumerateLogsNeedingUpload:(void (^)(ORKDataLogger *dataLogger, NSURL *logFileUrl, BOOL *stop))block error:(NSError * __autoreleasing *)error;
/**
Unmarks the set of uploaded files.
@@ -532,7 +518,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if the operation succeeds; otherwise, `NO`.
*/
- (BOOL)unmarkUploadedFiles:(NSArray<NSURL *> *)fileURLs error:(NSError * _Nullable *)error;
- (BOOL)unmarkUploadedFiles:(NSArray<NSURL *> *)fileURLs error:(NSError * _Nullable __autoreleasing *)error;
/**
Removes a set of uploaded files.
@@ -546,7 +532,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if the operation succeeds; otherwise, `NO`.
*/
- (BOOL)removeUploadedFiles:(NSArray<NSURL *> *)fileURLs error:(NSError * _Nullable *)error;
- (BOOL)removeUploadedFiles:(NSArray<NSURL *> *)fileURLs error:(NSError * _Nullable __autoreleasing *)error;
/**
Removes old and uploaded logs to bring total bytes down to a threshold.
@@ -559,23 +545,7 @@ ORK_CLASS_AVAILABLE
@return `YES` if the operation succeeds; otherwise, `NO`.
*/
- (BOOL)removeOldAndUploadedLogsToThreshold:(unsigned long long)bytes error:(NSError * _Nullable *)error;
@end
@interface ORKDataLogger (Tests)
/// The file handle to which to write
- (nullable NSFileHandle *)fileHandle;
@end
@interface NSURL (ORKDataLogger)
- (BOOL)ork_isUploaded;
- (BOOL)ork_setUploaded:(BOOL)uploaded error:(NSError * _Nullable *)error;
- (BOOL)removeOldAndUploadedLogsToThreshold:(unsigned long long)bytes error:(NSError * _Nullable __autoreleasing *)error;
@end
+67 -74
View File
@@ -30,12 +30,13 @@
#import "ORKDataLogger.h"
#import "ORKHelpers_Internal.h"
#import "CMMotionActivity+ORKJSONDictionary.h"
#import "HKSample+ORKJSONDictionary.h"
#import <ResearchKit/ResearchKit.h>
#import "ORKHelpers.h"
#include <sys/xattr.h>
#import "ORKDataLogger_Private.h"
#import "HKSample+ORKJSONDictionary.h"
#import "CMMotionActivity+ORKJSONDictionary.h"
#import "ORKDefines_Private.h"
static const char *ORKDataLoggerUploadedAttr = "com.apple.ResearchKit.uploaded";
@@ -108,7 +109,7 @@ static NSString *const ORKDataLoggerManagerConfigurationFilename = @".ORKDataLog
return (string.integerValue != 0);
}
- (BOOL)ork_setUploaded:(BOOL)uploaded error:(NSError **)error {
- (BOOL)ork_setUploaded:(BOOL)uploaded error:(NSError * __autoreleasing *)error {
NSString *value = (uploaded ? @"1" : @"0");
NSData *encodedString = [value dataUsingEncoding:NSUTF8StringEncoding];
return [self ork_setData:encodedString forAttr:ORKDataLoggerUploadedAttr error:error];
@@ -132,12 +133,12 @@ static NSString *const ORKDataLoggerManagerConfigurationFilename = @".ORKDataLog
return data;
}
- (BOOL)ork_setData:(NSData *)data forAttr:(const char *)attr error:(NSError **)error {
- (BOOL)ork_setData:(NSData *)data forAttr:(const char *)attr error:(NSError * __autoreleasing *)error {
const char *path = [self fileSystemRepresentation];
int rc = setxattr(path, attr, data.bytes, data.length, 0, 0);
if (rc != 0) {
if (error) {
*error = [NSError errorWithDomain:NSCocoaErrorDomain code:rc userInfo:@{NSLocalizedDescriptionKey: ORKLocalizedString(@"ERROR_DATALOGGER_SET_ATTRIBUTE", nil)}];
*error = [NSError errorWithDomain:NSCocoaErrorDomain code:rc userInfo:@{NSLocalizedDescriptionKey : ORKLocalizedString(@"ERROR_DATALOGGER_SET_ATTRIBUTE", nil)}];
}
}
return (rc == 0);
@@ -238,11 +239,11 @@ static void *ORKObjectObserverContext = &ORKObjectObserverContext;
return [object isKindOfClass:[NSData class]];
}
- (BOOL)beginLogWithFileHandle:(NSFileHandle *)fileHandle error:(NSError **)error {
- (BOOL)beginLogWithFileHandle:(NSFileHandle *)fileHandle error:(NSError * __autoreleasing *)error {
return YES;
}
- (BOOL)writeData:(NSData *)data fileHandle:(NSFileHandle *)fileHandle error:(NSError **)error {
- (BOOL)writeData:(NSData *)data fileHandle:(NSFileHandle *)fileHandle error:(NSError * __autoreleasing *)error {
BOOL result = YES;
@try {
[fileHandle writeData:data];
@@ -250,7 +251,7 @@ static void *ORKObjectObserverContext = &ORKObjectObserverContext;
@catch (NSException *exception) {
result = NO;
if (error) {
*error = [NSError errorWithDomain:ORKErrorDomain code:ORKErrorException userInfo:@{@"exception": exception}];
*error = [NSError errorWithDomain:ORKErrorDomain code:ORKErrorException userInfo:@{@"exception" : exception}];
}
}
return result;
@@ -265,14 +266,14 @@ static void *ORKObjectObserverContext = &ORKObjectObserverContext;
[fileHandle truncateFileAtOffset:offset];
}
- (BOOL)appendObject:(id)object fileHandle:(NSFileHandle *)fileHandle error:(NSError **)error {
- (BOOL)appendObject:(id)object fileHandle:(NSFileHandle *)fileHandle error:(NSError * __autoreleasing *)error {
if (![self canAcceptLogObject:object]) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"ORKLogFormatter accepts NSData only" userInfo:nil];
}
return [self writeData:(NSData *)object fileHandle:fileHandle error:error];
}
- (BOOL)appendObjects:(NSArray *)objects fileHandle:(NSFileHandle *)fileHandle error:(NSError **)error {
- (BOOL)appendObjects:(NSArray *)objects fileHandle:(NSFileHandle *)fileHandle error:(NSError * __autoreleasing *)error {
unsigned long long checkpoint = [self checkpointWithFileHandle:fileHandle];
NSError *errorOut = nil;
@@ -326,7 +327,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
return [object isKindOfClass:[NSDictionary class]] && [NSJSONSerialization isValidJSONObject:object];
}
- (BOOL)beginLogWithFileHandle:(NSFileHandle *)fileHandle error:(NSError **)error {
- (BOOL)beginLogWithFileHandle:(NSFileHandle *)fileHandle error:(NSError * __autoreleasing *)error {
// Write valid JSON containing no objects
NSData *data = [kJSONLogEmptyLogString dataUsingEncoding:NSUTF8StringEncoding];
return [self writeData:data fileHandle:fileHandle error:error];
@@ -347,7 +348,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
}
}
- (BOOL)appendObject:(id)object fileHandle:(NSFileHandle *)fileHandle error:(NSError **)error {
- (BOOL)appendObject:(id)object fileHandle:(NSFileHandle *)fileHandle error:(NSError * __autoreleasing *)error {
return [self appendObjects:@[object] fileHandle:fileHandle error:error];
}
@@ -359,7 +360,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
* before writing. When writing, we write a separator (if needed), the JSON
* object being appended, and the footer bytes.
*/
- (BOOL)appendObjects:(NSArray *)objects fileHandle:(NSFileHandle *)fileHandle error:(NSError **)error {
- (BOOL)appendObjects:(NSArray *)objects fileHandle:(NSFileHandle *)fileHandle error:(NSError * __autoreleasing *)error {
if (!fileHandle) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Filehandle is nil" userInfo:nil];
}
@@ -445,12 +446,10 @@ static NSInteger _ORKJSON_terminatorLength = 0;
return [[ORKDataLogger alloc] initWithDirectory:url logName:logName formatter:[ORKJSONLogFormatter new] delegate:delegate];
}
+ (instancetype)new {
ORKThrowMethodUnavailableException();
}
- (instancetype)init {
ORKThrowMethodUnavailableException();
return nil;
}
- (instancetype)initWithDirectory:(NSURL *)url logName:(NSString *)logName formatter:(ORKLogFormatter *)formatter delegate:(id<ORKDataLoggerDelegate>)delegate {
@@ -491,7 +490,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
@throw [NSException exceptionWithName:NSGenericException reason:[NSString stringWithFormat:@"%@ is not a class", configuration[@"formatterClass"]] userInfo:nil];
}
self = [self initWithDirectory:url logName:configuration[@"logName"] formatter:[[formatterClass alloc] init] delegate:delegate];
self = [self initWithDirectory:url logName:configuration[@"logName"] formatter:[formatterClass new] delegate:delegate];
if (self) {
// Don't notify about initial setup
[_observer pause];
@@ -503,11 +502,11 @@ static NSInteger _ORKJSON_terminatorLength = 0;
}
- (NSDictionary *)configuration {
return @{@"logName": self.logName,
@"formatterClass": NSStringFromClass([self.logFormatter class]),
@"fileProtectionMode": @(self.fileProtectionMode),
@"maximumCurrentLogFileSize": @(self.maximumCurrentLogFileSize),
@"maximumCurrentLogFileLifetime": @(self.maximumCurrentLogFileLifetime)
return @{@"logName" : self.logName,
@"formatterClass" : NSStringFromClass([self.logFormatter class]),
@"fileProtectionMode" : @(self.fileProtectionMode),
@"maximumCurrentLogFileSize" : @(self.maximumCurrentLogFileSize),
@"maximumCurrentLogFileLifetime" : @(self.maximumCurrentLogFileLifetime)
};
}
@@ -528,9 +527,9 @@ static NSInteger _ORKJSON_terminatorLength = 0;
if (_directorySource) {
dispatch_source_set_cancel_handler(_directorySource, ^{ close(dirFD); });
ORKWeakTypeOf(self) weakSelf = self;
__weak __typeof(self) weakSelf = self;
dispatch_source_set_event_handler(_directorySource, ^{
ORKStrongTypeOf(self) strongSelf = weakSelf;
__strong __typeof(self) strongSelf = weakSelf;
[strongSelf directoryUpdated];
});
dispatch_resume(_directorySource);
@@ -571,7 +570,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
return _currentFileHandle;
}
- (BOOL)enumerateLogs:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError **)error {
- (BOOL)enumerateLogs:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError * __autoreleasing *)error {
if (!block) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Block parameter is required" userInfo:nil];
}
@@ -583,7 +582,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
return success;
}
- (BOOL)enumerateLogsUploaded:(BOOL)uploaded block:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError **)error {
- (BOOL)enumerateLogsUploaded:(BOOL)uploaded block:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError * __autoreleasing *)error {
if (!block) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Block parameter is required" userInfo:nil];
}
@@ -595,15 +594,15 @@ static NSInteger _ORKJSON_terminatorLength = 0;
return success;
}
- (BOOL)enumerateLogsNeedingUpload:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError **)error {
- (BOOL)enumerateLogsNeedingUpload:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError * __autoreleasing *)error {
return [self enumerateLogsUploaded:NO block:block error:error];
}
- (BOOL)enumerateLogsAlreadyUploaded:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError **)error {
- (BOOL)enumerateLogsAlreadyUploaded:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError * __autoreleasing *)error {
return [self enumerateLogsUploaded:YES block:block error:error];
}
- (BOOL)append:(id)object error:(NSError **)error {
- (BOOL)append:(id)object error:(NSError * __autoreleasing *)error {
if (!object) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Nil object" userInfo:nil];
}
@@ -614,7 +613,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
return success;
}
- (BOOL)appendObjects:(NSArray *)objects error:(NSError **)error {
- (BOOL)appendObjects:(NSArray *)objects error:(NSError * __autoreleasing *)error {
if (!objects.count) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Empty array" userInfo:nil];
}
@@ -625,7 +624,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
return success;
}
- (BOOL)markFileUploaded:(BOOL)uploaded atURL:(NSURL *)url error:(NSError **)error {
- (BOOL)markFileUploaded:(BOOL)uploaded atURL:(NSURL *)url error:(NSError * __autoreleasing *)error {
__block BOOL success = NO;
dispatch_sync(_queue, ^{
success = [self queue_markFileUploaded:uploaded atURL:url error:error];
@@ -633,7 +632,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
return success;
}
- (BOOL)removeUploadedFiles:(NSArray<NSURL *> *)fileURLs withError:(NSError **)error {
- (BOOL)removeUploadedFiles:(NSArray<NSURL *> *)fileURLs withError:(NSError * __autoreleasing *)error {
__block BOOL success = NO;
dispatch_sync(_queue, ^{
success = [self queue_removeUploadedFiles:fileURLs withError:error];
@@ -641,7 +640,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
return success;
}
- (BOOL)removeAllFilesWithError:(NSError **)error {
- (BOOL)removeAllFilesWithError:(NSError * __autoreleasing *)error {
__block BOOL success = NO;
dispatch_sync(_queue, ^{
success = [self queue_removeAllFilesWithError:error];
@@ -687,7 +686,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
});
}
- (BOOL)queue_enumerateLogs:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError **)error {
- (BOOL)queue_enumerateLogs:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError * __autoreleasing *)error {
static NSArray *keys = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
@@ -745,7 +744,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
return (errorOut ? NO : YES);
}
- (BOOL)queue_enumerateLogsUploaded:(BOOL)uploaded block:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError **)error {
- (BOOL)queue_enumerateLogsUploaded:(BOOL)uploaded block:(void (^)(NSURL *logFileUrl, BOOL *stop))block error:(NSError * __autoreleasing *)error {
return [self queue_enumerateLogs:^(NSURL *logFileUrl, BOOL *stop) {
NSError *errorOut = nil;
BOOL wantUploaded = [logFileUrl ork_isUploaded];
@@ -759,7 +758,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
} error:error];
}
- (NSFileHandle *)queue_makeFileHandleWithError:(NSError **)error {
- (NSFileHandle *)queue_makeFileHandleWithError:(NSError * __autoreleasing *)error {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *url = [self currentLogFileURL];
@@ -785,7 +784,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
BOOL success = [fileManager createFileAtPath:filePath contents:nil attributes:nil];
if (!success) {
if (error) {
*error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileNoSuchFileError userInfo:@{NSLocalizedDescriptionKey: ORKLocalizedString(@"ERROR_DATALOGGER_CREATE_FILE", nil)}];
*error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileNoSuchFileError userInfo:@{NSLocalizedDescriptionKey : ORKLocalizedString(@"ERROR_DATALOGGER_CREATE_FILE", nil)}];
}
return nil;
}
@@ -800,7 +799,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
assert(fileHandle);
// Set file protection after opening the file, so that class B works as expected.
BOOL success = [fileManager setAttributes:@{NSFileProtectionKey: ORKFileProtectionFromMode(self.fileProtectionMode)} ofItemAtPath:[url path] error:error];
BOOL success = [fileManager setAttributes:@{NSFileProtectionKey : ORKFileProtectionFromMode(self.fileProtectionMode)} ofItemAtPath:[url path] error:error];
// Allow formatter to initialize the log file with header content
success = success && [self.logFormatter beginLogWithFileHandle:fileHandle error:error];
@@ -815,7 +814,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
return _currentFileHandle;
}
- (NSFileHandle *)queue_fileHandleWithError:(NSError **)error {
- (NSFileHandle *)queue_fileHandleWithError:(NSError * __autoreleasing *)error {
if (!_currentFileHandle) {
_currentFileHandle = [self queue_makeFileHandleWithError:error];
@@ -825,15 +824,15 @@ static NSInteger _ORKJSON_terminatorLength = 0;
}
+ (NSURL *)nextUrlForDirectoryUrl:(NSURL *)directory logName:(NSString *)logName {
static NSDateFormatter *dateFromatter = nil;
static NSDateFormatter *dfm = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
dateFromatter = [NSDateFormatter new];
[dateFromatter setLocale:[NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]];
dateFromatter.dateFormat = @"yyyyMMddHHmmss";
dfm = [NSDateFormatter new];
[dfm setLocale:[NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]];
dfm.dateFormat = @"yyyyMMddHHmmss";
});
NSString *datedLog = [NSString stringWithFormat:@"%@-%@",logName, [dateFromatter stringFromDate:[NSDate date]]];
NSString *datedLog = [NSString stringWithFormat:@"%@-%@",logName, [dfm stringFromDate:[NSDate date]]];
NSURL *destinationUrl = [directory URLByAppendingPathComponent:datedLog];
NSFileManager *fileManager = [NSFileManager defaultManager];
@@ -869,8 +868,8 @@ static NSInteger _ORKJSON_terminatorLength = 0;
if (self.fileProtectionMode == ORKFileProtectionCompleteUnlessOpen) {
// Upgrade to complete file protection after roll-over
NSError *error = nil;
if (![fileManager setAttributes:@{NSFileProtectionKey: NSFileProtectionComplete}
ofItemAtPath:[destinationUrl path] error:&error]) {
if (![fileManager setAttributes:@{NSFileProtectionKey : NSFileProtectionComplete}
ofItemAtPath:[destinationUrl path] error:&error]) {
ORK_Log_Warning(@"Error setting NSFileProtectionComplete on %@: %@", destinationUrl, error);
}
}
@@ -908,7 +907,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
[self queue_closeAndRenameLog];
}
- (BOOL)queue_append:(id)object error:(NSError **)error {
- (BOOL)queue_append:(id)object error:(NSError * __autoreleasing *)error {
[self queue_rolloverIfNeeded];
NSFileHandle *fileHandle = [self queue_fileHandleWithError:error];
@@ -926,7 +925,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
return result;
}
- (BOOL)queue_appendObjects:(NSArray *)objects error:(NSError **)error {
- (BOOL)queue_appendObjects:(NSArray *)objects error:(NSError * __autoreleasing *)error {
[self queue_rolloverIfNeeded];
NSFileHandle *fileHandle = [self queue_fileHandleWithError:error];
@@ -943,13 +942,13 @@ static NSInteger _ORKJSON_terminatorLength = 0;
return result;
}
- (BOOL)queue_markFileUploaded:(BOOL)uploaded atURL:(NSURL *)url error:(NSError **)error {
- (BOOL)queue_markFileUploaded:(BOOL)uploaded atURL:(NSURL *)url error:(NSError * __autoreleasing *)error {
BOOL success = [url ork_setUploaded:uploaded error:error];
[self queue_setNeedsUpdateBytes];
return success;
}
- (BOOL)queue_removeUploadedFiles:(NSArray<NSURL *> *)fileURLs withError:(NSError **)error {
- (BOOL)queue_removeUploadedFiles:(NSArray<NSURL *> *)fileURLs withError:(NSError * __autoreleasing *)error {
NSFileManager *fileManager = [NSFileManager defaultManager];
__block NSMutableArray *errors = [NSMutableArray array];
BOOL success = [self queue_enumerateLogs:^(NSURL *logFileUrl, BOOL *stop) {
@@ -963,9 +962,7 @@ static NSInteger _ORKJSON_terminatorLength = 0;
}
} else {
// File was requested to be removed, but was not marked uploaded
[errors addObject:[NSError errorWithDomain:ORKErrorDomain
code:ORKErrorInvalidObject
userInfo:@{NSLocalizedDescriptionKey: ORKLocalizedString(@"ERROR_DATALOGGER_COULD_NOT_MAORK", nil), @"url": logFileUrl}]];
[errors addObject:[NSError errorWithDomain:ORKErrorDomain code:ORKErrorInvalidObject userInfo:@{NSLocalizedDescriptionKey : ORKLocalizedString(@"ERROR_DATALOGGER_COULD_NOT_MAORK", nil), @"url" : logFileUrl}]];
}
}
} error:error];
@@ -974,16 +971,14 @@ static NSInteger _ORKJSON_terminatorLength = 0;
if (errors.count) {
if (!success && error && *error) {
[errors addObject:*error];
*error = [NSError errorWithDomain:ORKErrorDomain
code:ORKErrorMultipleErrors
userInfo:@{NSLocalizedDescriptionKey: ORKLocalizedString(@"ERROR_DATALOGGER_MULTIPLE", nil), @"errors": errors}];
*error = [NSError errorWithDomain:ORKErrorDomain code:ORKErrorMultipleErrors userInfo:@{NSLocalizedDescriptionKey : ORKLocalizedString(@"ERROR_DATALOGGER_MULTIPLE", nil), @"errors" : errors}];
}
success = NO;
}
return success;
}
- (BOOL)queue_removeAllFilesWithError:(NSError **)error {
- (BOOL)queue_removeAllFilesWithError:(NSError * __autoreleasing *)error {
[_currentFileHandle closeFile];
_currentFileHandle = nil;
@@ -1047,12 +1042,10 @@ static NSInteger _ORKJSON_terminatorLength = 0;
@implementation ORKDataLoggerManager
+ (instancetype)new {
ORKThrowMethodUnavailableException();
}
- (instancetype)init {
ORKThrowMethodUnavailableException();
return nil;
}
- (instancetype)initWithDirectory:(NSURL *)directory delegate:(id<ORKDataLoggerManagerDelegate>)delegate {
@@ -1101,9 +1094,9 @@ static NSString *const LoggerConfigurationsKey = @"loggers";
- (NSDictionary *)queue_configuration {
NSMutableArray *loggerConfigurations = [_records.allValues valueForKey:@"configuration"];
return @{PendingUploadBytesThresholdKey: @(self.pendingUploadBytesThreshold),
TotalBytesThresholdKey: @(self.totalBytesThreshold),
LoggerConfigurationsKey: loggerConfigurations };
return @{PendingUploadBytesThresholdKey : @(self.pendingUploadBytesThreshold),
TotalBytesThresholdKey : @(self.totalBytesThreshold),
LoggerConfigurationsKey : loggerConfigurations };
}
- (void)queue_synchronizeConfiguration {
@@ -1182,7 +1175,7 @@ static NSString *const LoggerConfigurationsKey = @"loggers";
return logNames;
}
- (BOOL)queue_enumerateLogsNeedingUpload:(void (^)(ORKDataLogger *dataLogger, NSURL *logFileUrl, BOOL *stop))block error:(NSError **)error {
- (BOOL)queue_enumerateLogsNeedingUpload:(void (^)(ORKDataLogger *dataLogger, NSURL *logFileUrl, BOOL *stop))block error:(NSError * __autoreleasing *)error {
BOOL success = YES;
NSMutableArray *allFiles = [NSMutableArray array];
// Collect all the log file URLs so we can sort them by date rather than enumerating by logger.
@@ -1221,7 +1214,7 @@ static NSString *const LoggerConfigurationsKey = @"loggers";
return success;
}
- (BOOL)enumerateLogsNeedingUpload:(void (^)(ORKDataLogger *dataLogger, NSURL *logFileUrl, BOOL *stop))block error:(NSError **)error {
- (BOOL)enumerateLogsNeedingUpload:(void (^)(ORKDataLogger *dataLogger, NSURL *logFileUrl, BOOL *stop))block error:(NSError * __autoreleasing *)error {
if (!block) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Block argument required" userInfo:nil];
}
@@ -1233,7 +1226,7 @@ static NSString *const LoggerConfigurationsKey = @"loggers";
return success;
}
- (BOOL)queue_removeUploadedFiles:(NSArray<NSURL *> *)fileURLs error:(NSError **)error {
- (BOOL)queue_removeUploadedFiles:(NSArray<NSURL *> *)fileURLs error:(NSError * __autoreleasing *)error {
BOOL success = YES;
NSMutableArray *notRemoved = [NSMutableArray array];
for (NSURL *url in fileURLs) {
@@ -1256,7 +1249,7 @@ static NSString *const LoggerConfigurationsKey = @"loggers";
return success;
}
- (BOOL)removeUploadedFiles:(NSArray<NSURL *> *)fileURLs error:(NSError **)error {
- (BOOL)removeUploadedFiles:(NSArray<NSURL *> *)fileURLs error:(NSError * __autoreleasing *)error {
__block BOOL success = YES;
dispatch_sync(_queue, ^{
@@ -1265,7 +1258,7 @@ static NSString *const LoggerConfigurationsKey = @"loggers";
return success;
}
- (BOOL)queue_unmarkUploadedFiles:(NSArray<NSURL *> *)fileURLs error:(NSError **)error {
- (BOOL)queue_unmarkUploadedFiles:(NSArray<NSURL *> *)fileURLs error:(NSError * __autoreleasing *)error {
BOOL success = YES;
NSMutableArray<NSURL *> *notRemoved = [NSMutableArray array];
for (NSURL *url in fileURLs) {
@@ -1288,7 +1281,7 @@ static NSString *const LoggerConfigurationsKey = @"loggers";
return success;
}
- (BOOL)unmarkUploadedFiles:(NSArray<NSURL *> *)fileURLs error:(NSError **)error {
- (BOOL)unmarkUploadedFiles:(NSArray<NSURL *> *)fileURLs error:(NSError *__autoreleasing *)error {
__block BOOL success = YES;
dispatch_sync(_queue, ^{
success = [self queue_unmarkUploadedFiles:fileURLs error:error];
@@ -1296,7 +1289,7 @@ static NSString *const LoggerConfigurationsKey = @"loggers";
return success;
}
- (BOOL)queue_removeOldAndUploadedLogsToThreshold:(unsigned long long)bytes error:(NSError **)error {
- (BOOL)queue_removeOldAndUploadedLogsToThreshold:(unsigned long long)bytes error:(NSError *__autoreleasing *)error {
if (bytes == 0) {
for (ORKDataLogger *logger in _records) {
[logger removeAllFilesWithError:nil];
@@ -1353,7 +1346,7 @@ static NSString *const LoggerConfigurationsKey = @"loggers";
return (totalBytes <= bytes);
}
- (BOOL)removeOldAndUploadedLogsToThreshold:(unsigned long long)bytes error:(NSError **)error {
- (BOOL)removeOldAndUploadedLogsToThreshold:(unsigned long long)bytes error:(NSError *__autoreleasing *)error {
__block BOOL success = YES;
dispatch_sync(_queue, ^{
success = [self queue_removeOldAndUploadedLogsToThreshold:bytes error:error];
@@ -29,21 +29,33 @@
*/
@import UIKit;
#import "ORKStepViewController.h"
#import <ResearchKit/ResearchKit.h>
NS_ASSUME_NONNULL_BEGIN
/**
The `ORKSignatureStepViewController` class is a step view controller subclass
used to manage a signature step (`ORKSignatureStep`).
You should not need to instantiate a signature step view controller directly. Instead, include
a signature step in a task, and present a task view controller for that stask.
/*
Exposing a minimal set of extra facilities to permit unit testing.
*/
ORK_CLASS_AVAILABLE
@interface ORKSignatureStepViewController : ORKStepViewController
@interface ORKDataLogger ()
- (nullable NSFileHandle *)fileHandle;
@end
@protocol ORKDataLoggerExtendedDelegate <ORKDataLoggerDelegate>
@optional
- (void)dataLoggerThresholdsDidChange:(ORKDataLogger *)dataLogger;
@end
@interface NSURL (ORKDataLogger)
- (BOOL)ork_isUploaded;
- (BOOL)ork_setUploaded:(BOOL)uploaded error:(NSError * __autoreleasing *)error;
@end
@@ -28,11 +28,8 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@import UIKit;
#import <ResearchKit/ORKRecorder.h>
NS_ASSUME_NONNULL_BEGIN
@class CMDeviceMotion;
@@ -30,16 +30,13 @@
#import "ORKDeviceMotionRecorder.h"
#import "ORKDataLogger.h"
#import "ORKHelpers.h"
#import "ORKRecorder_Internal.h"
#import "ORKHelpers_Internal.h"
#import "ORKRecorder_Private.h"
#import "ORKDataLogger.h"
#import <CoreMotion/CoreMotion.h>
#import "CMDeviceMotion+ORKJSONDictionary.h"
@import CoreMotion;
@interface ORKDeviceMotionRecorder () {
ORKDataLogger *_logger;
@@ -88,10 +85,10 @@
[super start];
if (!_logger) {
NSError *error = nil;
_logger = [self makeJSONDataLoggerWithError:&error];
NSError *err = nil;
_logger = [self makeJSONDataLoggerWithError:&err];
if (!_logger) {
[self finishRecordingWithError:error];
[self finishRecordingWithError:err];
return;
}
}
+12 -15
View File
@@ -30,16 +30,12 @@
#import "ORKFitnessContentView.h"
#import "ORKHelpers.h"
#import <CoreMotion/CoreMotion.h>
#import "ORKSkin.h"
#import "ORKActiveStepQuantityView.h"
#import "ORKTintedImageView.h"
#import "ORKHelpers_Internal.h"
#import "ORKSkin.h"
@import CoreMotion;
@import HealthKit;
// #define LAYOUT_TEST 1
// #define LAYOUT_DEBUG 1
@@ -329,18 +325,19 @@
}
- (void)updateTimerLabel {
static NSDateComponentsFormatter *formatter = nil;
static NSDateComponentsFormatter *_formatter = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
formatter = [NSDateComponentsFormatter new];
formatter.unitsStyle = NSDateComponentsFormatterUnitsStylePositional;
formatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorPad;
formatter.allowedUnits = NSCalendarUnitMinute | NSCalendarUnitSecond;
NSDateComponentsFormatter *fmt = [NSDateComponentsFormatter new];
fmt.unitsStyle = NSDateComponentsFormatterUnitsStylePositional;
fmt.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorPad;
fmt.allowedUnits = NSCalendarUnitMinute | NSCalendarUnitSecond;
_formatter = fmt;
});
NSString *labelString = [formatter stringFromTimeInterval:MAX(round(_timeLeft),0)];
_timerLabel.text = labelString;
_timerLabel.hidden = (labelString == nil);
NSString *s = [_formatter stringFromTimeInterval:MAX(round(_timeLeft),0)];
_timerLabel.text = s;
_timerLabel.hidden = (s == nil);
}
@end
+1 -6
View File
@@ -29,13 +29,10 @@
*/
@import Foundation;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ResearchKit.h>
#import <ResearchKit/ORKActiveStep.h>
NS_ASSUME_NONNULL_BEGIN
/**
Fitness step.
@@ -48,5 +45,3 @@ ORK_CLASS_AVAILABLE
@interface ORKFitnessStep : ORKActiveStep
@end
NS_ASSUME_NONNULL_END
-1
View File
@@ -30,7 +30,6 @@
#import "ORKFitnessStep.h"
#import "ORKFitnessStepViewController.h"
@@ -29,13 +29,9 @@
*/
@import Foundation;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStepViewController.h>
#import <ResearchKit/ResearchKit_Private.h>
NS_ASSUME_NONNULL_BEGIN
/**
Step view controller corresponding to `ORKFitnessStep`.
@@ -46,5 +42,3 @@ ORK_CLASS_AVAILABLE
@interface ORKFitnessStepViewController : ORKActiveStepViewController
@end
NS_ASSUME_NONNULL_END
@@ -30,21 +30,16 @@
#import "ORKFitnessStepViewController.h"
#import "ORKActiveStepTimer.h"
#import "ORKActiveStepView.h"
#import "ORKHelpers.h"
#import "ORKStep_Private.h"
#import "ORKStepViewController_Internal.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKFitnessContentView.h"
#import "ORKVerticalContainerView.h"
#import "ORKStepViewController_Internal.h"
#import "ORKFitnessStep.h"
#import "ORKHealthQuantityTypeRecorder.h"
#import "ORKPedometerRecorder.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKFitnessStep.h"
#import "ORKStep_Private.h"
#import "ORKHelpers_Internal.h"
#import "ORKActiveStepView.h"
@interface ORKFitnessStepViewController () <ORKHealthQuantityTypeRecorderDelegate,ORKPedometerRecorderDelegate> {
@@ -29,7 +29,6 @@
*/
@import UIKit;
#import <ResearchKit/ORKRecorder.h>
@@ -30,7 +30,7 @@
#import "ORKHealthQuantityTypeRecorder.h"
#import "ORKHelpers_Internal.h"
#import "ORKHelpers.h"
#import "ORKDataLogger.h"
#import "ORKRecorder_Private.h"
#import "ORKRecorder_Internal.h"
@@ -43,29 +43,12 @@
HKHealthStore *_healthStore;
NSPredicate *_samplePredicate;
HKObserverQuery *_observerQuery;
/// Either the HKQueryAnchor object *or* NSUInteger value are tracked since the initializer for
/// iOS 8 and iOS 9 use different objects. Only one will actually be referenced in the initalizer.
HKQueryAnchor *_anchor;
NSUInteger _anchorValue;
NSInteger _anchor;
HKQuantitySample *_lastSample;
}
@end
#ifdef __IPHONE_10_0
/// Add a protocol defining the initializer for iOS 8 apps. This signature was deprecated in iOS 9
/// and deleted in iOS 10.
@interface HKAnchoredObjectQuery (iOS8)
- (instancetype)initWithType:(HKSampleType *)type
predicate:(NSPredicate *)predicate
anchor:(NSUInteger)anchor
limit:(NSUInteger)limit
completionHandler:(void (^)(HKAnchoredObjectQuery *query,
NSArray<__kindof HKSample *> *results,
NSUInteger newAnchor,
NSError *error))handler NS_DEPRECATED_IOS(8_0, 9_0);
@end
#endif
@implementation ORKHealthQuantityTypeRecorder
@@ -84,8 +67,7 @@
_quantityType = quantityType;
_unit = unit;
self.continuesInBackground = YES;
_anchorValue = HKAnchoredObjectQueryNoAnchor;
_anchor = [HKQueryAnchor anchorFromValue:_anchorValue];
_anchor = HKAnchoredObjectQueryNoAnchor;
}
return self;
}
@@ -107,7 +89,7 @@
static const NSInteger _HealthAnchoredQueryLimit = 100;
- (void)query_logResults:(NSArray *)results withAnchor:(HKQueryAnchor*)newAnchor anchorValue:(NSUInteger)anchorValue {
- (void)query_logResults:(NSArray *)results withAnchor:(NSUInteger)newAnchor {
NSUInteger resultCount = results.count;
if (resultCount == 0) {
@@ -131,7 +113,6 @@ static const NSInteger _HealthAnchoredQueryLimit = 100;
}
_anchor = newAnchor;
_anchorValue = anchorValue;
if (resultCount == _HealthAnchoredQueryLimit) {
// Do another fetch immediately rather than wait for an observation
@@ -147,45 +128,23 @@ static const NSInteger _HealthAnchoredQueryLimit = 100;
NSAssert(_samplePredicate != nil, @"Sample predicate should be non-nil if recording");
__weak typeof(self) weakSelf = self;
void (^handleResults)(NSArray <__kindof HKSample *> *, HKQueryAnchor *, NSUInteger, NSError *) = ^ (NSArray *results, HKQueryAnchor *newAnchor, NSUInteger newAnchorValue, NSError *error) {
if (error) {
// An error in the query's not the end of the world: we'll probably get another chance. Just log it.
ORK_Log_Warning(@"Anchored query error: %@", error);
return;
}
__typeof(self) strongSelf = weakSelf;
[strongSelf query_logResults:results withAnchor:newAnchor anchorValue:newAnchorValue];
};
HKAnchoredObjectQuery *anchoredQuery;
if ([HKAnchoredObjectQuery instancesRespondToSelector:@selector(initWithType:predicate:anchor:limit:resultsHandler:)]) {
anchoredQuery = [[HKAnchoredObjectQuery alloc] initWithType:_quantityType
predicate:_samplePredicate
anchor:_anchor
limit:_HealthAnchoredQueryLimit
resultsHandler:
^(HKAnchoredObjectQuery *query, NSArray *sampleObjects, NSArray *deletedObjects, HKQueryAnchor *newAnchor, NSError *error) {
handleResults(sampleObjects, newAnchor, 0, error);
}];
} else if ([HKAnchoredObjectQuery instancesRespondToSelector:@selector(initWithType:predicate:anchor:limit:completionHandler:)]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
anchoredQuery = [[HKAnchoredObjectQuery alloc] initWithType:_quantityType
predicate:_samplePredicate
anchor:_anchorValue
limit:_HealthAnchoredQueryLimit
completionHandler:
^(HKAnchoredObjectQuery *query, NSArray<__kindof HKSample *> *results, NSUInteger newAnchor, NSError *error) {
handleResults(results, nil, newAnchor, error);
}];
#pragma clang diagnostic pop
}
else {
NSAssert(NO, @"Could not instantiate an HKAnchoredObjectQuery.");
}
HKAnchoredObjectQuery *anchoredQuery = [[HKAnchoredObjectQuery alloc]
initWithType:_quantityType
predicate:_samplePredicate
anchor:_anchor
limit:_HealthAnchoredQueryLimit
completionHandler:^(HKAnchoredObjectQuery *query, NSArray *results, NSUInteger newAnchor, NSError *error)
{
if (error) {
// An error in the query's not the end of the world: we'll probably get another chance. Just log it.
ORK_Log_Warning(@"Anchored query error: %@", error);
return;
}
__typeof(self) strongSelf = weakSelf;
[strongSelf query_logResults:results withAnchor:newAnchor];
}];
[_healthStore executeQuery:anchoredQuery];
}
@@ -29,9 +29,7 @@
*/
@import UIKit;
#import "ORKCustomStepView_Internal.h"
#import "ORKTypes.h"
NS_ASSUME_NONNULL_BEGIN
@@ -30,12 +30,10 @@
#import "ORKHolePegTestPlaceContentView.h"
#import "ORKDirectionView.h"
#import "ORKHolePegTestPlaceHoleView.h"
#import "ORKHolePegTestPlacePegView.h"
#import "ORKHelpers_Internal.h"
#import "ORKHolePegTestPlaceHoleView.h"
#import "ORKDirectionView.h"
#import "ORKHelpers.h"
#import "ORKSkin.h"
@@ -165,7 +163,7 @@ static const CGFloat ORKHolePegViewDiameter = 88.0f;
NSMutableArray *constraintsArray = [NSMutableArray array];
NSDictionary *views = NSDictionaryOfVariableBindings(_progressView, _pegView, _holeView, _directionView);
NSDictionary *metrics = @{@"diameter": @(ORKHolePegViewDiameter)};
NSDictionary *metrics = @{@"diameter" : @(ORKHolePegViewDiameter)};
[constraintsArray addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_progressView]-|"
@@ -29,14 +29,13 @@
*/
@import UIKit;
#import "ORKDefines.h"
#import <ResearchKit/ResearchKit_Private.h>
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKHolePegTestPlaceHoleView : UIView <CAAnimationDelegate>
@interface ORKHolePegTestPlaceHoleView : UIView
@property (nonatomic, assign, getter = isRotated) BOOL rotated;
@property (nonatomic, assign, getter = isSuccess) BOOL success;
@@ -31,8 +31,6 @@
#import "ORKHolePegTestPlaceHoleView.h"
#import "ORKHelpers_Internal.h"
static const CGFloat ORKPlaceHoleViewRotation = 45.0f;
@@ -163,9 +161,9 @@ static const CGFloat ORKPlaceHoleViewRotation = 45.0f;
}
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag {
ORKWeakTypeOf(self) weakSelf = self;
__weak typeof(self) weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.7f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
ORKStrongTypeOf(self) strongSelf = weakSelf;
typeof(self) strongSelf = weakSelf;
strongSelf.success = NO;
});
}
@@ -29,8 +29,7 @@
*/
@import UIKit;
#import "ORKDefines.h"
#import <ResearchKit/ResearchKit_Private.h>
NS_ASSUME_NONNULL_BEGIN
@@ -29,9 +29,7 @@
*/
@import Foundation;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStep.h>
#import <ResearchKit/ResearchKit_Private.h>
NS_ASSUME_NONNULL_BEGIN
@@ -30,7 +30,6 @@
#import "ORKHolePegTestPlaceStep.h"
#import "ORKHolePegTestPlaceStepViewController.h"
@@ -74,7 +73,7 @@
}
if (self.stepDuration < ORKHolePegTestMinimumDuration) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"duration cannot be shorter than %@ seconds.", @(ORKHolePegTestMinimumDuration)] userInfo:nil];
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"duration can not be shorter than %@ seconds.", @(ORKHolePegTestMinimumDuration)] userInfo:nil];
}
}
@@ -29,9 +29,7 @@
*/
@import UIKit;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStepViewController.h>
#import <ResearchKit/ResearchKit_Private.h>
NS_ASSUME_NONNULL_BEGIN
@@ -30,19 +30,11 @@
#import "ORKHolePegTestPlaceStepViewController.h"
#import "ORKActiveStepView.h"
#import "ORKHolePegTestPlaceContentView.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKStepViewController_Internal.h"
#import "ORKTaskViewController.h"
#import "ORKHolePegTestPlaceStep.h"
#import "ORKNavigableOrderedTask.h"
#import "ORKResult.h"
#import "ORKHelpers_Internal.h"
#import "ORKHolePegTestPlaceContentView.h"
#import "ORKActiveStepViewController_internal.h"
#import "ORKStepViewController_internal.h"
#import "ORKActiveStepView.h"
@interface ORKHolePegTestPlaceStepViewController () <ORKHolePegTestPlaceContentViewDelegate>
@@ -29,9 +29,7 @@
*/
@import UIKit;
#import "ORKCustomStepView_Internal.h"
#import "ORKTypes.h"
NS_ASSUME_NONNULL_BEGIN
@@ -30,12 +30,10 @@
#import "ORKHolePegTestRemoveContentView.h"
#import "ORKDirectionView.h"
#import "ORKHolePegTestRemovePegView.h"
#import "ORKSeparatorView.h"
#import "ORKHelpers_Internal.h"
#import "ORKDirectionView.h"
#import "ORKHelpers.h"
#import "ORKSkin.h"
@@ -158,7 +156,7 @@ static const CGFloat PegViewSeparatorWidth = 2.0f;
NSMutableArray *constraintsArray = [NSMutableArray array];
NSDictionary *views = NSDictionaryOfVariableBindings(_progressView, _container, _pegView, _separatorView, _directionView);
NSDictionary *metrics = @{@"diameter": @(PegViewDiameter), @"separator": @(PegViewSeparatorWidth), @"margin": @((1 + self.threshold) * PegViewDiameter)};
NSDictionary *metrics = @{@"diameter" : @(PegViewDiameter), @"separator" : @(PegViewSeparatorWidth), @"margin" : @((1 + self.threshold) * PegViewDiameter)};
[constraintsArray addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_progressView]-|"
@@ -29,14 +29,13 @@
*/
@import UIKit;
#import "ORKDefines.h"
#import <ResearchKit/ResearchKit_Private.h>
NS_ASSUME_NONNULL_BEGIN
ORK_CLASS_AVAILABLE
@interface ORKHolePegTestRemovePegView : UIView <CAAnimationDelegate>
@interface ORKHolePegTestRemovePegView : UIView
@property (nonatomic, assign, getter = isSuccess) BOOL success;
@@ -29,9 +29,7 @@
*/
@import Foundation;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStep.h>
#import <ResearchKit/ResearchKit_Private.h>
NS_ASSUME_NONNULL_BEGIN
@@ -30,7 +30,6 @@
#import "ORKHolePegTestRemoveStep.h"
#import "ORKHolePegTestRemoveStepViewController.h"
@@ -74,7 +73,7 @@
}
if (self.stepDuration < ORKHolePegTestMinimumDuration) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"duration cannot be shorter than %@ seconds.", @(ORKHolePegTestMinimumDuration)] userInfo:nil];
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"duration can not be shorter than %@ seconds.", @(ORKHolePegTestMinimumDuration)] userInfo:nil];
}
}
@@ -29,9 +29,7 @@
*/
@import UIKit;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStepViewController.h>
#import <ResearchKit/ResearchKit_Private.h>
NS_ASSUME_NONNULL_BEGIN
@@ -30,18 +30,11 @@
#import "ORKHolePegTestRemoveStepViewController.h"
#import "ORKActiveStepView.h"
#import "ORKHolePegTestRemoveContentView.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKStepViewController_Internal.h"
#import "ORKTaskViewController.h"
#import "ORKHolePegTestRemoveStep.h"
#import "ORKHelpers_Internal.h"
#import "ORKResult.h"
#import "ORKHolePegTestRemoveContentView.h"
#import "ORKActiveStepViewController_internal.h"
#import "ORKStepViewController_internal.h"
#import "ORKActiveStepView.h"
@interface ORKHolePegTestRemoveStepViewController () <ORKHolePegTestRemoveContentViewDelegate>
@@ -29,9 +29,8 @@
*/
@import UIKit;
@import CoreLocation;
#import <ResearchKit/ORKRecorder.h>
#import <CoreLocation/CoreLocation.h>
NS_ASSUME_NONNULL_BEGIN
+8 -11
View File
@@ -30,14 +30,11 @@
#import "ORKLocationRecorder.h"
#import "ORKDataLogger.h"
#import "ORKRecorder_Internal.h"
#import "CLLocation+ORKJSONDictionary.h"
#import <CoreLocation/CoreLocation.h>
#import "CLLocation+ORKJSONDictionary.h"
#import "ORKDataLogger.h"
#import "ORKRecorder_Internal.h"
#import "ORKRecorder_Private.h"
@interface ORKLocationRecorder () <CLLocationManagerDelegate> {
@@ -79,10 +76,10 @@
[super start];
if (!_logger) {
NSError *error = nil;
_logger = [self makeJSONDataLoggerWithError:&error];
NSError *err = nil;
_logger = [self makeJSONDataLoggerWithError:&err];
if (!_logger) {
[self finishRecordingWithError:error];
[self finishRecordingWithError:err];
return;
}
}
@@ -97,7 +94,7 @@
if (!self.locationManager) {
NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain
code:NSFeatureUnsupportedError
userInfo:@{@"recorder": self}];
userInfo:@{@"recorder" : self}];
[self finishRecordingWithError:error];
return;
}
+1 -2
View File
@@ -29,8 +29,7 @@
*/
@import UIKit;
#import "ORKTypes.h"
#import <ResearchKit/ResearchKit_Private.h>
#import "ORKCustomStepView_Internal.h"
+3 -5
View File
@@ -30,14 +30,12 @@
#import "ORKPSATContentView.h"
#import "ORKBorderedButton.h"
#import "ORKSkin.h"
#import "ORKPSATKeyboardView.h"
#import "ORKTapCountLabel.h"
#import "ORKBorderedButton.h"
#import "ORKVoiceEngine.h"
#import "ORKHelpers_Internal.h"
#import "ORKSkin.h"
#import "ORKHelpers.h"
@interface ORKPSATContentView ()
@@ -29,8 +29,7 @@
*/
@import UIKit;
#import "ORKDefines.h"
#import <ResearchKit/ResearchKit.h>
NS_ASSUME_NONNULL_BEGIN
@@ -30,7 +30,6 @@
#import "ORKPSATKeyboardView.h"
#import "ORKBorderedButton.h"
+1 -3
View File
@@ -29,9 +29,7 @@
*/
@import Foundation;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStep.h>
#import <ResearchKit/ResearchKit_Private.h>
NS_ASSUME_NONNULL_BEGIN
-1
View File
@@ -30,7 +30,6 @@
#import "ORKPSATStep.h"
#import "ORKPSATStepViewController.h"
@@ -29,9 +29,7 @@
*/
@import UIKit;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStepViewController.h>
#import <ResearchKit/ResearchKit_Private.h>
NS_ASSUME_NONNULL_BEGIN
@@ -30,19 +30,13 @@
#import "ORKPSATStepViewController.h"
#import "ORKActiveStepTimer.h"
#import "ORKActiveStepView.h"
#import "ORKPSATContentView.h"
#import "ORKPSATKeyboardView.h"
#import "ORKVerticalContainerView.h"
#import "ORKActiveStepViewController_Internal.h"
#import "ORKPSATStep.h"
#import "ORKResult.h"
#import "ORKStepViewController_Internal.h"
#import "ORKHelpers_Internal.h"
#import "ORKPSATContentView.h"
#import "ORKPSATStep.h"
#import "ORKVerticalContainerView.h"
#import "ORKActiveStepView.h"
#import "ORKPSATKeyboardView.h"
@interface ORKPSATStepViewController () <ORKPSATKeyboardViewDelegate>
@@ -161,12 +155,12 @@
([self psatStep].interStimulusInterval - [self psatStep].stimulusDuration) > 0.05 ) {
// Don't show `-` if the difference between stimulusDuration and interStimulusInterval is less than timer's resolution.
ORKWeakTypeOf(self) weakSelf = self;
__weak typeof(self) weakSelf = self;
self.clearDigitsTimer = [[ORKActiveStepTimer alloc] initWithDuration:[self psatStep].stepDuration
interval:[self psatStep].interStimulusInterval
runtime:-[self psatStep].stimulusDuration
handler:^(ORKActiveStepTimer *timer, BOOL finished) {
ORKStrongTypeOf(self) strongSelf = weakSelf;
typeof(self) strongSelf = weakSelf;
[strongSelf clearDigitsTimerFired];
}];
[self.clearDigitsTimer resume];
@@ -29,7 +29,6 @@
*/
@import UIKit;
#import <ResearchKit/ORKRecorder.h>
+9 -12
View File
@@ -30,13 +30,10 @@
#import "ORKPedometerRecorder.h"
#import "ORKDataLogger.h"
#import "ORKRecorder_Internal.h"
#import "ORKHelpers_Internal.h"
#import "CMPedometerData+ORKJSONDictionary.h"
#import "ORKRecorder_Internal.h"
#import "ORKRecorder_Private.h"
@interface ORKPedometerRecorder () {
@@ -94,10 +91,10 @@
_totalDistance = -1;
if (!_logger) {
NSError *error = nil;
_logger = [self makeJSONDataLoggerWithError:&error];
NSError *err = nil;
_logger = [self makeJSONDataLoggerWithError:&err];
if (!_logger) {
[self finishRecordingWithError:error];
[self finishRecordingWithError:err];
return;
}
}
@@ -107,25 +104,25 @@
if (![[self.pedometer class] isStepCountingAvailable]) {
[self finishRecordingWithError:[NSError errorWithDomain:NSCocoaErrorDomain
code:NSFeatureUnsupportedError
userInfo:@{@"recorder": self}]];
userInfo:@{@"recorder" : self}]];
return;
}
_isRecording = YES;
ORKWeakTypeOf(self) weakSelf = self;
__weak __typeof(self) weakSelf = self;
[self.pedometer startPedometerUpdatesFromDate:[NSDate date] withHandler:^(CMPedometerData *pedometerData, NSError *error) {
BOOL success = NO;
if (pedometerData) {
success = [_logger append:[pedometerData ork_JSONDictionary] error:&error];
dispatch_async(dispatch_get_main_queue(), ^{
ORKStrongTypeOf(self) strongSelf = weakSelf;
__typeof(self) strongSelf = weakSelf;
[strongSelf updateStatisticsWithData:pedometerData];
});
}
if (!success || error) {
dispatch_async(dispatch_get_main_queue(), ^{
ORKStrongTypeOf(self) strongSelf = weakSelf;
__typeof(self) strongSelf = weakSelf;
[strongSelf finishRecordingWithError:error];
});
}
@@ -29,12 +29,9 @@
*/
@import UIKit;
#import "ORKCustomStepView_Internal.h"
NS_ASSUME_NONNULL_BEGIN
@interface ORKReactionTimeContentView : ORKActiveStepCustomView
- (void)setStimulusHidden:(BOOL)hidden;
@@ -46,5 +43,3 @@ NS_ASSUME_NONNULL_BEGIN
- (void)resetAfterDelay:(NSTimeInterval)delay completion:(nullable void (^)(void))completion;
@end
NS_ASSUME_NONNULL_END
@@ -30,9 +30,8 @@
#import "ORKReactionTimeContentView.h"
#import "ORKNavigationContainerView.h"
#import "ORKReactionTimeStimulusView.h"
#import "ORKNavigationContainerView.h"
@implementation ORKReactionTimeContentView {
@@ -26,13 +26,11 @@
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
*/
@import Foundation;
@import AudioToolbox;
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStep.h>
#import <ResearchKit/ResearchKit.h>
#import <AudioToolbox/AudioServices.h>
NS_ASSUME_NONNULL_BEGIN
@@ -30,10 +30,8 @@
#import "ORKReactionTimeStep.h"
#import "ORKReactionTimeViewController.h"
#import "ORKHelpers_Internal.h"
#import "ORKHelpers.h"
@implementation ORKReactionTimeStep
@@ -29,12 +29,9 @@
*/
@import UIKit;
#import "ORKCustomStepView_Internal.h"
NS_ASSUME_NONNULL_BEGIN
@interface ORKReactionTimeStimulusView : UIView
- (void)reset;
@@ -44,5 +41,3 @@ NS_ASSUME_NONNULL_BEGIN
- (void)startFailureAnimationWithDuration:(NSTimeInterval)duration completion:(nullable void(^)(void))completion;
@end
NS_ASSUME_NONNULL_END
@@ -26,12 +26,10 @@
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
*/
@import UIKit;
#import "ORKDefines.h"
#import "ORKActiveStepViewController.h"
#import <ResearchKit/ResearchKit.h>
NS_ASSUME_NONNULL_BEGIN

Some files were not shown because too many files have changed in this diff Show More