YHNativeMotion.m 4.13 KB
//
//  YHNativeMotion.m
//  YohoExplorerDemo
//
//  Created by gaoqiang xu on 4/13/15.
//  Copyright (c) 2015 gaoqiang xu. All rights reserved.
//

#import "YHNativeMotion.h"
@import UIKit;
@import AudioToolbox;
@import CoreMotion;

NSString * const YHNative_Motion = @"Native_Motion";

// g constant: -9.81 m/s^2
#define kGravitationalConstant -9.81

@interface YHNativeMotion ()

@property (nonatomic, strong) CMMotionManager *motionManager;
@property (assign) BOOL haveReturnedResult;
@property (assign) BOOL isRunning;
@property (assign) double x;
@property (assign) double y;
@property (assign) double z;
@property (assign) NSTimeInterval timestamp;
@property (assign) NSTimeInterval period;// 单位是毫秒

@end

@implementation YHNativeMotion

- (instancetype)init
{
    self = [super init];
    if (self) {
        _isRunning = NO;
        _haveReturnedResult = NO;
        _period = 10;// 默认10ms
        _timestamp = 0;
    }
    
    return self;
}

- (void)dealloc
{
    [self clearWatchAcceleration];
}

- (NSString *)actionName
{
    return YHNative_Motion;
}

- (CMMotionManager *)motionManager
{
    if (!_motionManager) {
        _motionManager = [[CMMotionManager alloc] init];
    }
    return _motionManager;
}

- (NSArray *)availableFunctions
{
    return @[ @"vibrate", @"watchAcceleration", @"clearWatchAcceleration" ];
}

- (void)vibrate
{
    NSInteger cycle = 1;
    if (self.options && self.options[@"duration"]) {
        float duration = [self.options[@"duration"] floatValue];
        cycle = ceilf(duration / .4);
        if (cycle < 1) {
            cycle = 1;
        }
    }
    
    for (NSUInteger i=0; i<cycle; i++) {
        if (i==0) {
            AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
        } else {
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(i * .3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
            });
        }
    }
    
    self.successCallBack(nil, NO, nil);
}

- (void)clearWatchAcceleration
{
    if ([self.motionManager isAccelerometerAvailable]) {
        if (self.haveReturnedResult == NO){
            // block has not fired before stop was called, return whatever result we currently have
            [self returnInfo];
        }
        [self.motionManager stopAccelerometerUpdates];
    }
    self.isRunning = NO;
    
    self.successCallBack(nil, NO, nil);
}

- (void)watchAcceleration
{
    if (self.options && self.options[@"period"]) {
        self.period = [self.options[@"period"] doubleValue];
    }
    self.haveReturnedResult = NO;
    
    if ([self.motionManager isAccelerometerAvailable]) {
        // Assign the update interval to the motion manager and start updates
        [self.motionManager setAccelerometerUpdateInterval:self.period/1000];  // expected in seconds
        __weak typeof(self)weakSelf = self;
        [self.motionManager startAccelerometerUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {
            NSTimeInterval ts = ([[NSDate date] timeIntervalSince1970] * 1000);
            weakSelf.x = accelerometerData.acceleration.x;
            weakSelf.y = accelerometerData.acceleration.y;
            weakSelf.z = accelerometerData.acceleration.z;
            weakSelf.timestamp = ts;
            [weakSelf returnInfo];
        }];
        
        if (!self.isRunning) {
            self.isRunning = YES;
        }
    } else {
        self.failureCallBack(@"This device does not support accelerometer !");
    }
}

- (void)returnInfo
{
    // Create an acceleration object
    NSMutableDictionary* accelProps = [NSMutableDictionary dictionaryWithCapacity:4];
    
    [accelProps setValue:[NSNumber numberWithDouble:self.x * kGravitationalConstant] forKey:@"x"];
    [accelProps setValue:[NSNumber numberWithDouble:self.y * kGravitationalConstant] forKey:@"y"];
    [accelProps setValue:[NSNumber numberWithDouble:self.z * kGravitationalConstant] forKey:@"z"];
    [accelProps setValue:[NSNumber numberWithDouble:self.timestamp] forKey:@"timestamp"];
    
    self.successCallBack(accelProps, YES, nil);
    self.haveReturnedResult = YES;
}

@end