├── ANCS iOS ├── en.lproj │ └── InfoPlist.strings ├── ANCSViewController.h ├── ANCSAppDelegate.h ├── ANCS iOS-Prefix.pch ├── main.m ├── Images.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── LaunchImage.launchimage │ │ └── Contents.json ├── ANCS iOS-Info.plist ├── ANCSViewController.m ├── ANCSAppDelegate.m └── Base.lproj │ └── Main.storyboard ├── Mac ANCS ├── en.lproj │ ├── InfoPlist.strings │ └── Credits.rtf ├── ANCS-Prefix.pch ├── main.m ├── JPANCSAppDelegate.h ├── ANCSAppNameTransaction.h ├── ANCSNotificationCenter.h ├── ANCSNotificationDetailTransaction.h ├── ANCSDetailTuple.h ├── ANCSNotificationDetails.h ├── ANCSNotificationDetails.m ├── ANCSNotificationCenter.m ├── Images.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── ANCSTransaction.h ├── ANCS-Info.plist ├── ANCSNotification.h ├── ANCSNotification.m ├── ANCSDetailTuple.m ├── ANCSAppNameTransaction.m ├── JPANCSAppDelegate.m ├── ANCSTransaction.m ├── ANCSController.h ├── ANCSNotificationDetailTransaction.m ├── ANCSController.m └── Base.lproj │ └── MainMenu.xib ├── ANCS iOSTests ├── en.lproj │ └── InfoPlist.strings ├── ANCS iOSTests-Info.plist └── ANCS_iOSTests.m ├── Mac ANCSTests ├── en.lproj │ └── InfoPlist.strings ├── ANCSTests-Info.plist └── Mac_ANCSTests.m ├── ANCS iOSTests copy-Info.plist ├── README.md └── ANCS.xcodeproj └── project.pbxproj /ANCS iOS/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Mac ANCS/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /ANCS iOSTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Mac ANCSTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Mac ANCS/ANCS-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #ifdef __OBJC__ 8 | #import 9 | #endif 10 | -------------------------------------------------------------------------------- /ANCS iOS/ANCSViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANCSViewController.h 3 | // ANCS iOS 4 | // 5 | // Created by Jamie Pinkham on 9/23/13. 6 | // Copyright (c) 2013 Jamie Pinkham. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ANCSViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Mac ANCS/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Mac ANCS 4 | // 5 | // Created by Jamie Pinkham on 9/20/13. 6 | // Copyright (c) 2013 Jamie Pinkham. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, const char * argv[]) 12 | { 13 | return NSApplicationMain(argc, argv); 14 | } 15 | -------------------------------------------------------------------------------- /ANCS iOS/ANCSAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANCSAppDelegate.h 3 | // ANCS iOS 4 | // 5 | // Created by Jamie Pinkham on 9/23/13. 6 | // Copyright (c) 2013 Jamie Pinkham. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ANCSAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Mac ANCS/JPANCSAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // JPANCSAppDelegate.h 3 | // Mac ANCS 4 | // 5 | // Created by Jamie Pinkham on 9/20/13. 6 | // Copyright (c) 2013 Jamie Pinkham. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface JPANCSAppDelegate : NSObject 12 | 13 | @property (assign) IBOutlet NSWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Mac ANCS/ANCSAppNameTransaction.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANCSAppNameTransaction.h 3 | // ANCS 4 | // 5 | // Created by Jamie Pinkham on 9/22/13. 6 | // Copyright (c) 2013 Jamie Pinkham. All rights reserved. 7 | // 8 | 9 | #import "ANCSTransaction.h" 10 | 11 | @interface ANCSAppNameTransaction : ANCSTransaction 12 | 13 | - (instancetype)initWithAppIdentifier:(NSString *)appIdentifier; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /ANCS iOS/ANCS iOS-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /ANCS iOS/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // ANCS iOS 4 | // 5 | // Created by Jamie Pinkham on 9/23/13. 6 | // Copyright (c) 2013 Jamie Pinkham. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "ANCSAppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([ANCSAppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Mac ANCS/ANCSNotificationCenter.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANCSNotificationCenter.h 3 | // Mac ANCS 4 | // 5 | // Created by Jamie Pinkham on 9/20/13. 6 | // Copyright (c) 2013 Jamie Pinkham. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ANCSNotificationCenter : NSObject 12 | 13 | @property (nonatomic, assign) CFUUIDRef UUID; 14 | @property (nonatomic, copy) NSString *name; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /ANCS iOS/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Mac ANCS/ANCSNotificationDetailTransaction.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANCSNotificationDetailTransaction.h 3 | // Mac ANCS 4 | // 5 | // Created by Jamie Pinkham on 9/22/13. 6 | // Copyright (c) 2013 Jamie Pinkham. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ANCSController.h" 11 | #import "ANCSTransaction.h" 12 | 13 | @interface ANCSNotificationDetailTransaction : ANCSTransaction 14 | 15 | - (instancetype)initWithNotification:(ANCSNotification *)note detailsMask:(ANCSNotificationDetailsTypeMask)mask; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Mac ANCS/en.lproj/Credits.rtf: -------------------------------------------------------------------------------- 1 | {\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;} 2 | {\colortbl;\red255\green255\blue255;} 3 | \paperw9840\paperh8400 4 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural 5 | 6 | \f0\b\fs24 \cf0 Engineering: 7 | \b0 \ 8 | Some people\ 9 | \ 10 | 11 | \b Human Interface Design: 12 | \b0 \ 13 | Some other people\ 14 | \ 15 | 16 | \b Testing: 17 | \b0 \ 18 | Hopefully not nobody\ 19 | \ 20 | 21 | \b Documentation: 22 | \b0 \ 23 | Whoever\ 24 | \ 25 | 26 | \b With special thanks to: 27 | \b0 \ 28 | Mom\ 29 | } 30 | -------------------------------------------------------------------------------- /ANCS iOS/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Mac ANCS/ANCSDetailTuple.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANCSNotificationDetailTuple.h 3 | // Mac ANCS 4 | // 5 | // Created by Jamie Pinkham on 9/22/13. 6 | // Copyright (c) 2013 Jamie Pinkham. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ANCSController.h" 11 | 12 | @interface ANCSDetailTuple : NSObject 13 | 14 | @property (nonatomic, assign) uint8_t attributeIdentifier; 15 | @property (nonatomic, assign) uint16_t length; 16 | @property (nonatomic, readonly, getter = isComplete) BOOL complete; 17 | @property (nonatomic, readonly) NSString *value; 18 | 19 | - (NSData *)appendData:(NSData *)data; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /Mac ANCS/ANCSNotificationDetails.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANCSNotificationDetails.h 3 | // Mac ANCS 4 | // 5 | // Created by Jamie Pinkham on 9/21/13. 6 | // Copyright (c) 2013 Jamie Pinkham. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface ANCSNotificationDetails : NSObject 13 | 14 | @property (nonatomic, assign) uint16_t notificationId; 15 | @property (nonatomic, copy) NSString *appIdentifier; 16 | @property (nonatomic, copy) NSString *title; 17 | @property (nonatomic, copy) NSString *subtitle; 18 | @property (nonatomic, copy) NSString *message; 19 | @property (nonatomic, copy) NSString *messageSize; 20 | @property (nonatomic, copy) NSDate *date; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /ANCS iOSTests copy-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.jamiepinkham.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Mac ANCSTests/ANCSTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.jamiepinkham.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /ANCS iOSTests/ANCS iOSTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.jamiepinkham.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /ANCS iOSTests/ANCS_iOSTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANCS_iOSTests.m 3 | // ANCS iOSTests 4 | // 5 | // Created by Jamie Pinkham on 9/23/13. 6 | // Copyright (c) 2013 Jamie Pinkham. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ANCS_iOSTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation ANCS_iOSTests 16 | 17 | - (void)setUp 18 | { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown 24 | { 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | [super tearDown]; 27 | } 28 | 29 | - (void)testExample 30 | { 31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /Mac ANCSTests/Mac_ANCSTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // Mac_ANCSTests.m 3 | // Mac ANCSTests 4 | // 5 | // Created by Jamie Pinkham on 9/20/13. 6 | // Copyright (c) 2013 Jamie Pinkham. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface Mac_ANCSTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation Mac_ANCSTests 16 | 17 | - (void)setUp 18 | { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown 24 | { 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | [super tearDown]; 27 | } 28 | 29 | - (void)testExample 30 | { 31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /Mac ANCS/ANCSNotificationDetails.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANCSNotificationDetails.m 3 | // Mac ANCS 4 | // 5 | // Created by Jamie Pinkham on 9/21/13. 6 | // Copyright (c) 2013 Jamie Pinkham. All rights reserved. 7 | // 8 | 9 | #import "ANCSNotificationDetails.h" 10 | 11 | 12 | @implementation ANCSNotificationDetails 13 | 14 | - (NSString *)description 15 | { 16 | NSMutableString *ret = [[NSMutableString alloc] init]; 17 | [ret appendFormat:@"{\n\t appIdentifier : %@",self.appIdentifier]; 18 | [ret appendFormat:@"\n\t notificationId : %hu", self.notificationId]; 19 | [ret appendFormat:@"\n\t title : %@", self.title]; 20 | [ret appendFormat:@"\n\t subtitle : %@", self.subtitle]; 21 | [ret appendFormat:@"\n\t message : %@", self.message]; 22 | [ret appendFormat:@"\n\t messageSize : %@", self.messageSize]; 23 | [ret appendFormat:@"\n\t date : %@", self.date]; 24 | [ret appendFormat:@"\n}"]; 25 | return ret; 26 | } 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /Mac ANCS/ANCSNotificationCenter.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANCSNotificationCenter.m 3 | // Mac ANCS 4 | // 5 | // Created by Jamie Pinkham on 9/20/13. 6 | // Copyright (c) 2013 Jamie Pinkham. All rights reserved. 7 | // 8 | 9 | #import "ANCSNotificationCenter.h" 10 | 11 | @implementation ANCSNotificationCenter 12 | 13 | - (id)copyWithZone:(NSZone *)zone 14 | { 15 | ANCSNotificationCenter *copy = [[ANCSNotificationCenter alloc] init]; 16 | copy->_name = self.name; 17 | copy->_UUID = self.UUID; 18 | return copy; 19 | } 20 | 21 | - (BOOL)isEqual:(id)object 22 | { 23 | if(![object isKindOfClass:[self class]]) 24 | { 25 | return NO; 26 | } 27 | ANCSNotificationCenter *other = (ANCSNotificationCenter *)object; 28 | return CFEqual(self.UUID, other.UUID); 29 | } 30 | 31 | - (BOOL)isEqualTo:(id)object 32 | { 33 | return [self isEqual:object]; 34 | } 35 | 36 | - (NSUInteger)hash 37 | { 38 | NSString *value = CFBridgingRelease(CFUUIDCreateString(NULL, self.UUID)); 39 | return [value hash]; 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /Mac ANCS/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "size" : "16x16", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "size" : "16x16", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "size" : "32x32", 16 | "scale" : "1x" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "size" : "32x32", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "size" : "128x128", 26 | "scale" : "1x" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "size" : "128x128", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "size" : "256x256", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "size" : "256x256", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "size" : "512x512", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "size" : "512x512", 51 | "scale" : "2x" 52 | } 53 | ], 54 | "info" : { 55 | "version" : 1, 56 | "author" : "xcode" 57 | } 58 | } -------------------------------------------------------------------------------- /Mac ANCS/ANCSTransaction.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANCSTransaction.h 3 | // ANCS 4 | // 5 | // Created by Jamie Pinkham on 9/22/13. 6 | // Copyright (c) 2013 Jamie Pinkham. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class ANCSTransaction; 12 | 13 | typedef void(^ANCSTransactionCompletionBlock)(id result, NSError *error); 14 | 15 | typedef NS_ENUM(uint8_t, ANCSTransactionType) 16 | { 17 | ANCSTransactionTypeNotificationDetails, 18 | ANCSTransactionTypeAppDetails, 19 | ANCSTransactionTypeUnknown, 20 | }; 21 | 22 | @interface ANCSTransaction : NSObject 23 | 24 | @property (nonatomic, readonly, getter = isComplete) BOOL complete; 25 | @property (nonatomic, readonly) ANCSTransactionType transactionType; 26 | @property (nonatomic, readonly) NSData *transactionData; 27 | @property (nonatomic, readonly) NSUUID *identifier; 28 | @property (nonatomic, readonly) NSInteger headerLength; 29 | @property (nonatomic, readonly) NSDictionary *tuples; 30 | @property (nonatomic, readonly) NSError *error; 31 | @property (nonatomic, copy) ANCSTransactionCompletionBlock completionBlock; 32 | 33 | - (NSData *)buildCommandData; 34 | 35 | - (void)appendData:(NSData *)data; 36 | 37 | - (id)result; 38 | 39 | @end -------------------------------------------------------------------------------- /Mac ANCS/ANCS-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | com.jamiepinkham.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSMinimumSystemVersion 26 | ${MACOSX_DEPLOYMENT_TARGET} 27 | NSHumanReadableCopyright 28 | Copyright © 2013 Jamie Pinkham. All rights reserved. 29 | NSMainNibFile 30 | MainMenu 31 | NSPrincipalClass 32 | NSApplication 33 | 34 | 35 | -------------------------------------------------------------------------------- /ANCS iOS/ANCS iOS-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.jamiepinkham.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Mac ANCS/ANCSNotification.h: -------------------------------------------------------------------------------- 1 | // 2 | // JPANCSNotificationSource.h 3 | // Mac ANCS 4 | // 5 | // Created by Jamie Pinkham on 9/20/13. 6 | // Copyright (c) 2013 Jamie Pinkham. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef NS_ENUM(NSUInteger, ANCSEventNotificationType) 12 | { 13 | ANCSEventNotificationTypeAdded = 0, 14 | ANCSEventNotificationTypeModified = 1, 15 | ANCSEventNotificationTypeRemoved = 2, 16 | ANCSEventNotificationTypeReserved, 17 | }; 18 | 19 | typedef NS_OPTIONS(NSUInteger, ANCSEventFlag) 20 | { 21 | ANCSEventFlagSilent = (1 << 0), 22 | ANCSEventFlagImportant = ( 1 << 1), 23 | }; 24 | 25 | typedef NS_ENUM(NSInteger, ANCSCategory) 26 | { 27 | ANCSCategoryOther, 28 | ANCSCategoryIncomingCall, 29 | ANCSCategoryMissedCall, 30 | ANCSCategoryVoicemail, 31 | ANCSCategorySocial, 32 | ANCSCategorySchedule, 33 | ANCSCategoryEmail, 34 | ANCSCategoryNews, 35 | ANCSCategoryHealthAndFitness, 36 | ANCSCategoryBusinessAndFinance, 37 | ANCSCategoryLocation, 38 | ANCSCategoryEntertainment, 39 | }; 40 | 41 | @interface ANCSNotification : NSObject 42 | 43 | - (instancetype)initWithData:(NSData *)data; 44 | 45 | @property (nonatomic, readonly) NSInteger eventId; 46 | @property (nonatomic, readonly) NSInteger categoryCount; 47 | @property (nonatomic, readonly) ANCSEventNotificationType notificationType; 48 | @property (nonatomic, readonly) ANCSEventFlag eventFlags; 49 | @property (nonatomic, readonly) ANCSCategory category; 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /Mac ANCS/ANCSNotification.m: -------------------------------------------------------------------------------- 1 | // 2 | // JPANCSNotificationSource.m 3 | // Mac ANCS 4 | // 5 | // Created by Jamie Pinkham on 9/20/13. 6 | // Copyright (c) 2013 Jamie Pinkham. All rights reserved. 7 | // 8 | 9 | #import "ANCSNotification.h" 10 | 11 | @implementation ANCSNotification 12 | 13 | - (instancetype)initWithData:(NSData *)data 14 | { 15 | self = [super init]; 16 | if (self) 17 | { 18 | [data getBytes:&_notificationType range:NSMakeRange(0, 1)]; 19 | [data getBytes:&_eventFlags range:NSMakeRange(1, 1)]; 20 | [data getBytes:&_category range:NSMakeRange(2, 1)]; 21 | [data getBytes:&_categoryCount range:NSMakeRange(3, 1)]; 22 | uint32_t eventId; 23 | [data getBytes:&eventId range:NSMakeRange(4, 4)]; 24 | _eventId = CFSwapInt32LittleToHost(eventId); 25 | } 26 | return self; 27 | } 28 | 29 | - (BOOL)isEqual:(id)object 30 | { 31 | return [self isEqualTo:object]; 32 | } 33 | 34 | - (BOOL)isEqualTo:(id)object 35 | { 36 | if(![object isKindOfClass:[self class]]) 37 | { 38 | return NO; 39 | } 40 | ANCSNotification *other = (ANCSNotification *)object; 41 | return [other eventId] == [self eventId]; 42 | } 43 | 44 | - (NSUInteger)hash 45 | { 46 | return self.eventId; 47 | } 48 | 49 | - (NSString *)description 50 | { 51 | NSMutableString *ret = [[NSMutableString alloc] init]; 52 | [ret appendFormat:@"{\n\t eventId : %lu",self.eventId]; 53 | [ret appendFormat:@"\n\t categoryCount : %lu", self.categoryCount]; 54 | [ret appendFormat:@"\n\t notificationType : %lu", self.notificationType]; 55 | [ret appendFormat:@"\n\t eventFlags : %lu", self.eventFlags]; 56 | [ret appendFormat:@"\n\t category : %lu", self.category]; 57 | [ret appendFormat:@"\n}"]; 58 | return ret; 59 | } 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /Mac ANCS/ANCSDetailTuple.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANCSNotificationDetailTuple.m 3 | // Mac ANCS 4 | // 5 | // Created by Jamie Pinkham on 9/22/13. 6 | // Copyright (c) 2013 Jamie Pinkham. All rights reserved. 7 | // 8 | 9 | #import "ANCSDetailTuple.h" 10 | 11 | #define HEADER_SIZE 3 12 | 13 | @interface ANCSDetailTuple () 14 | 15 | @property (nonatomic, strong) NSMutableData *data; 16 | 17 | @end 18 | 19 | @implementation ANCSDetailTuple 20 | 21 | - (instancetype)init 22 | { 23 | self = [super init]; 24 | if (self) 25 | { 26 | 27 | } 28 | return self; 29 | } 30 | 31 | - (BOOL)isComplete 32 | { 33 | return _data != nil && _data.length == self.length; 34 | } 35 | 36 | 37 | - (NSData *)appendData:(NSData *)data 38 | { 39 | if(!self.complete) 40 | { 41 | if(_data == nil) 42 | { 43 | _data = [[NSMutableData alloc] init]; 44 | } 45 | [self.data appendData:data]; 46 | uint16_t length = self.length; 47 | if([self.data length] > length) 48 | { 49 | NSData *extra = [self.data subdataWithRange:NSMakeRange(length, [self.data length] - length)]; 50 | self.data = [[self.data subdataWithRange:NSMakeRange(0, length)] mutableCopy]; 51 | return extra; 52 | } 53 | } 54 | return nil; 55 | } 56 | 57 | - (NSString *)value 58 | { 59 | NSData *data = [self.data subdataWithRange:NSMakeRange(HEADER_SIZE, [self.data length] - HEADER_SIZE)]; 60 | return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 61 | } 62 | 63 | - (uint16_t)length 64 | { 65 | if(self.data == nil) 66 | { 67 | return UINT16_MAX; 68 | } 69 | if(self.data.length < HEADER_SIZE) 70 | { 71 | return UINT16_MAX; 72 | } 73 | uint16_t ret; 74 | [self.data getBytes:&ret range:NSMakeRange(sizeof(uint8_t), sizeof(uint16_t))]; 75 | return CFSwapInt16LittleToHost(ret) + HEADER_SIZE; 76 | } 77 | @end 78 | -------------------------------------------------------------------------------- /ANCS iOS/ANCSViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANCSViewController.m 3 | // ANCS iOS 4 | // 5 | // Created by Jamie Pinkham on 9/23/13. 6 | // Copyright (c) 2013 Jamie Pinkham. All rights reserved. 7 | // 8 | 9 | #import "ANCSViewController.h" 10 | #import 11 | 12 | #define DUMMY_SERVICE_UUID_STRING @"C00ED14C-1166-415E-9075-51989B9A6EC6" 13 | 14 | @interface ANCSViewController () 15 | 16 | @property (nonatomic, strong) CBPeripheralManager *peripheralManager; 17 | 18 | @end 19 | 20 | @implementation ANCSViewController 21 | 22 | - (void)viewDidLoad 23 | { 24 | [super viewDidLoad]; 25 | // Do any additional setup after loading the view, typically from a nib. 26 | } 27 | 28 | - (void)didReceiveMemoryWarning 29 | { 30 | [super didReceiveMemoryWarning]; 31 | // Dispose of any resources that can be recreated. 32 | } 33 | 34 | - (IBAction)startBroadcasting:(id)sender 35 | { 36 | self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:NULL]; 37 | } 38 | 39 | -(void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral 40 | { 41 | // Opt out from any other state 42 | if(peripheral.state == CBPeripheralManagerStateUnsupported || peripheral.state == CBPeripheralManagerStateUnauthorized) 43 | { 44 | return; 45 | } 46 | 47 | if(peripheral.state == CBPeripheralManagerStateResetting) 48 | { 49 | NSLog(@"resetting"); 50 | } 51 | 52 | if (peripheral.state != CBPeripheralManagerStatePoweredOn) 53 | { 54 | return; 55 | } 56 | 57 | CBMutableService *service = [[CBMutableService alloc] initWithType:[CBUUID UUIDWithString:DUMMY_SERVICE_UUID_STRING] primary:YES]; 58 | [self.peripheralManager addService:service]; 59 | [self.peripheralManager startAdvertising:nil]; 60 | } 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | BTLE_ANCS 2 | ========= 3 | 4 | A WIP for connecting to ANCS. 5 | 6 | [ANCS](https://developer.apple.com/library/ios/documentation/CoreBluetooth/Reference/AppleNotificationCenterServiceSpecification/Introduction/Introduction.html#//apple_ref/doc/uid/TP40013460-CH2-SW1) is a way for BTLE devices to connect to and read your Notification Center in iOS7. (Think Pebble). 7 | 8 | I wanted to see what it was all about, so I wrote a Mac client for ANCS. 9 | 10 | A few caveats: 11 | * I wrote this late and quick, it's not the best design. I've spent maybe 5 hours on it total. 12 | * Getting an app's display name [just doesn't work](https://devforums.apple.com/message/876984#876984). In the code's current state, ~~kicking off that transaction will deadlock the transaction queue~~ all transactions will timeout after 10 seconds if not completed. 13 | * You have to run the iOS app and tap start broadcasting in order for the Mac client to see the ANCS service. (No clue on that) 14 | * There's no UI. Just watch the log messages. 15 | * Best way to see it in action is get yourself all connected up and then send yourself an iMessage. 16 | 17 | ``` 18 | 2013-09-23 00:37:43.662 ANCS[28739:303] notification source characteristic is notifying = YES 19 | 2013-09-23 00:37:43.856 ANCS[28739:303] data source characteristic is notifying = YES 20 | 2013-09-23 00:37:57.307 ANCS[28739:303] added notification = { 21 | eventId : 43 22 | categoryCount : 6 23 | notificationType : 0 24 | eventFlags : 1 25 | category : 4 26 | } 27 | 2013-09-23 00:37:57.405 ANCS[28739:303] removed notification = { 28 | eventId : 40 29 | categoryCount : 5 30 | notificationType : 2 31 | eventFlags : 1 32 | category : 4 33 | } 34 | 2013-09-23 00:37:57.603 ANCS[28739:303] updated details = { 35 | appIdentifier : com.apple.MobileSMS 36 | notificationId : 43 37 | title : Jamie Pinkham 38 | subtitle : 39 | message : i am in your notification center, reading your notifications 40 | messageSize : 60 41 | date : 2013-09-23 04:37:00 +0000 42 | } 43 | ``` 44 | ![Screenshot here](http://d.pr/i/oYUD+ "Screenshot") 45 | -------------------------------------------------------------------------------- /ANCS iOS/ANCSAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANCSAppDelegate.m 3 | // ANCS iOS 4 | // 5 | // Created by Jamie Pinkham on 9/23/13. 6 | // Copyright (c) 2013 Jamie Pinkham. All rights reserved. 7 | // 8 | 9 | #import "ANCSAppDelegate.h" 10 | 11 | @implementation ANCSAppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 14 | { 15 | // Override point for customization after application launch. 16 | return YES; 17 | } 18 | 19 | - (void)applicationWillResignActive:(UIApplication *)application 20 | { 21 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 22 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 23 | } 24 | 25 | - (void)applicationDidEnterBackground:(UIApplication *)application 26 | { 27 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 28 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 29 | } 30 | 31 | - (void)applicationWillEnterForeground:(UIApplication *)application 32 | { 33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | - (void)applicationDidBecomeActive:(UIApplication *)application 37 | { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application 42 | { 43 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /Mac ANCS/ANCSAppNameTransaction.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANCSAppNameTransaction.m 3 | // ANCS 4 | // 5 | // Created by Jamie Pinkham on 9/22/13. 6 | // Copyright (c) 2013 Jamie Pinkham. All rights reserved. 7 | // 8 | 9 | #import "ANCSAppNameTransaction.h" 10 | #import "ANCSDetailTuple.h" 11 | 12 | static uint8_t const kANCSCommandIDGetAppName = 0x1; 13 | static uint8_t const kANCSAppAttributeIDDisplayName = 0x0; 14 | static uint16_t const kANCSAttributeMaxLength = 0xffff; 15 | 16 | @interface ANCSAppNameTransaction () 17 | { 18 | NSDictionary *_tuples; 19 | } 20 | 21 | @property (nonatomic, copy) NSString *appIdentifier; 22 | 23 | @end 24 | 25 | @implementation ANCSAppNameTransaction 26 | 27 | -(instancetype)initWithAppIdentifier:(NSString *)appIdentifier 28 | { 29 | self = [super init]; 30 | if(self) 31 | { 32 | _appIdentifier = appIdentifier; 33 | } 34 | return self; 35 | } 36 | 37 | - (NSInteger)headerLength 38 | { 39 | return [self.appIdentifier lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 2; 40 | } 41 | 42 | -(NSDictionary *)tuples 43 | { 44 | if(_tuples == nil) 45 | { 46 | _tuples = [self buildTuples]; 47 | } 48 | return _tuples; 49 | } 50 | 51 | - (NSData *)buildCommandData 52 | { 53 | NSMutableData *ret = [NSMutableData data]; 54 | 55 | [ret appendBytes:&kANCSCommandIDGetAppName length:sizeof(kANCSCommandIDGetAppName)]; 56 | const char *appIdentifierCString = [self.appIdentifier UTF8String]; 57 | [ret appendBytes:appIdentifierCString length:self.appIdentifier.length + 1]; 58 | [ret appendBytes:&kANCSAppAttributeIDDisplayName length:sizeof(kANCSAppAttributeIDDisplayName)]; 59 | 60 | return ret; 61 | } 62 | 63 | - (NSInteger)expectedLength 64 | { 65 | if(self.transactionData == nil) 66 | { 67 | return UINT16_MAX; 68 | } 69 | if(self.transactionData.length < self.headerLength) 70 | { 71 | return UINT16_MAX; 72 | } 73 | uint16_t ret; 74 | [self.transactionData getBytes:&ret range:NSMakeRange(sizeof(uint8_t), sizeof(uint16_t))]; 75 | return CFSwapInt16LittleToHost(ret) + self.headerLength; 76 | } 77 | 78 | - (id)result 79 | { 80 | if(self.complete) 81 | { 82 | NSData *data = [self.transactionData subdataWithRange:NSMakeRange(self.headerLength, [self.transactionData length] - self.headerLength)]; 83 | return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 84 | } 85 | return nil; 86 | } 87 | 88 | - (NSDictionary *)buildTuples 89 | { 90 | ANCSDetailTuple *tuple = [[ANCSDetailTuple alloc] init]; 91 | tuple.attributeIdentifier = kANCSAppAttributeIDDisplayName; 92 | return @{@(kANCSAppAttributeIDDisplayName) : tuple }; 93 | } 94 | 95 | @end 96 | -------------------------------------------------------------------------------- /Mac ANCS/JPANCSAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // JPANCSAppDelegate.m 3 | // Mac ANCS 4 | // 5 | // Created by Jamie Pinkham on 9/20/13. 6 | // Copyright (c) 2013 Jamie Pinkham. All rights reserved. 7 | // 8 | 9 | #import "JPANCSAppDelegate.h" 10 | #import "ANCSController.h" 11 | #import "ANCSNotificationCenter.h" 12 | #import "ANCSNotification.h" 13 | #import "ANCSNotificationDetails.h" 14 | 15 | @interface JPANCSAppDelegate () 16 | 17 | @property (nonatomic, strong) ANCSController *controller; 18 | 19 | @end 20 | 21 | @implementation JPANCSAppDelegate 22 | 23 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification 24 | { 25 | // Insert code here to initialize your application 26 | self.controller = [[ANCSController alloc] initWithDelegate:self queue:NULL]; 27 | [self.controller scanForNotificationCenters]; 28 | } 29 | 30 | - (void)controllerStartedScanningForNotificationCenters:(ANCSController *)controller 31 | { 32 | // NSLog(@"started scanning"); 33 | } 34 | - (void)controller:(ANCSController *)controller failedToStartScan:(NSError *)error 35 | { 36 | // NSLog(@"failed to scan"); 37 | } 38 | - (void)controller:(ANCSController *)controller foundNotificationCenter:(ANCSNotificationCenter *)notificationCenter 39 | { 40 | // NSLog(@"found notification center = %@", notificationCenter.name); 41 | [controller connectToNotificationCenter:notificationCenter]; 42 | } 43 | - (void)controller:(ANCSController *)controller connectedToNotificationCenter:(ANCSNotificationCenter *)notificationCenter 44 | { 45 | // NSLog(@"connected to notification center = %@", notificationCenter.name); 46 | } 47 | - (void)controller:(ANCSController *)controller failedToConnectToNotificationCenter:(ANCSNotificationCenter *)notificationCenter error:(NSError *)error 48 | { 49 | // NSLog(@"failed to connect = %@ name = %@", notificationCenter.name, error); 50 | } 51 | - (void)controller:(ANCSController *)controller disconnectedFromNotificationCenter:(ANCSNotificationCenter *)notificationCenter 52 | { 53 | // NSLog(@"disconnected from notification center = %@", notificationCenter.name); 54 | } 55 | - (void)controller:(ANCSController *)controller receivedNotification:(ANCSNotification *)notification notificationCenter:(ANCSNotificationCenter *)notificationCenter 56 | { 57 | if([notification notificationType] == ANCSEventNotificationTypeRemoved) 58 | { 59 | NSLog(@"removed notification = %@", notification); 60 | } 61 | else 62 | { 63 | NSLog(@"added notification = %@", notification); 64 | [controller getAttributesForNotification:notification detailsMask:ANCSNotificationDetailsTypeMaskAll notificationCenter:notificationCenter]; 65 | } 66 | } 67 | 68 | - (void)controller:(ANCSController *)controller didUpdateNotificationDetails:(ANCSNotificationDetails *)notificationDetails notificationCenter:(ANCSNotificationCenter *)notificationCenter 69 | { 70 | NSLog(@"updated details = %@", notificationDetails); 71 | [controller getApplicationNameForIdentifier:notificationDetails.appIdentifier onNotificationCenter:notificationCenter]; 72 | } 73 | 74 | - (void)controller:(ANCSController *)controller didRetrieveAppDisplayName:(NSString *)displayName forIdentifier:(NSString *)identifier 75 | { 76 | 77 | } 78 | 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /ANCS iOS/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Mac ANCS/ANCSTransaction.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANCSTransaction.m 3 | // ANCS 4 | // 5 | // Created by Jamie Pinkham on 9/22/13. 6 | // Copyright (c) 2013 Jamie Pinkham. All rights reserved. 7 | // 8 | 9 | #import "ANCSTransaction.h" 10 | #import "ANCSDetailTuple.h" 11 | 12 | @interface ANCSTransaction () 13 | 14 | @property (nonatomic, strong) NSMutableData *accumulatedData; 15 | @property (nonatomic, assign) ANCSDetailTuple *currentTuple; 16 | 17 | @end 18 | 19 | @implementation ANCSTransaction 20 | 21 | - (id)init 22 | { 23 | self = [super init]; 24 | if(self) 25 | { 26 | _accumulatedData = [[NSMutableData alloc] init]; 27 | _identifier = [NSUUID UUID]; 28 | } 29 | return self; 30 | } 31 | 32 | - (NSData *)buildCommandData 33 | { 34 | NSAssert(NO, @"subclasses should override: %@", NSStringFromSelector(_cmd)); 35 | return nil; 36 | } 37 | 38 | -(void)appendData:(NSData *)data 39 | { 40 | [self.accumulatedData appendData:data]; 41 | if(self.accumulatedData.length < self.headerLength) 42 | { 43 | return; 44 | } 45 | if(self.currentTuple == nil) 46 | { 47 | uint8_t type; 48 | [self.accumulatedData getBytes:&type range:NSMakeRange(self.headerLength, 1)]; 49 | self.currentTuple = self.tuples[@(type)]; 50 | data = [data subdataWithRange:NSMakeRange(5, [self.transactionData length] - self.headerLength)]; 51 | } 52 | NSData *leftOver = [[self currentTuple] appendData:data]; 53 | while(leftOver != nil) 54 | { 55 | uint8_t nextType; 56 | [leftOver getBytes:&nextType length:sizeof(uint8_t)]; 57 | self.currentTuple = self.tuples[@(nextType)]; 58 | leftOver = [[self currentTuple] appendData:leftOver]; 59 | } 60 | 61 | } 62 | 63 | - (NSData *)transactionData 64 | { 65 | return [self.accumulatedData copy]; 66 | } 67 | 68 | -(id)result 69 | { 70 | NSAssert(NO, @"subclasses should override: %@", NSStringFromSelector(_cmd)); 71 | return nil; 72 | } 73 | 74 | - (NSError *)error 75 | { 76 | if(!self.isComplete) 77 | { 78 | return [NSError errorWithDomain:@"com.jamiepinkham.ancs" code:-1001 userInfo:@{NSLocalizedDescriptionKey:@"transaction timed out"}]; 79 | } 80 | if(self.result == nil) 81 | { 82 | return [NSError errorWithDomain:@"com.jamiepinkham.ancs" code:-1002 userInfo:@{NSLocalizedDescriptionKey:@"invalid result"}]; 83 | } 84 | return nil; 85 | } 86 | 87 | - (BOOL)isComplete 88 | { 89 | if([self.transactionData length] < self.headerLength) 90 | { 91 | return NO; 92 | } 93 | __block BOOL complete = YES; 94 | [[self.tuples allValues] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 95 | ANCSDetailTuple *tuple = (ANCSDetailTuple *)obj; 96 | complete = [tuple isComplete]; 97 | if(!complete) 98 | { 99 | *stop = YES; 100 | } 101 | }]; 102 | return complete; 103 | } 104 | 105 | 106 | -(ANCSTransactionType)transactionType 107 | { 108 | ANCSTransactionType type = ANCSTransactionTypeUnknown; 109 | if([self.accumulatedData length] >= 3) 110 | { 111 | [self.accumulatedData getBytes:&type range:NSMakeRange(0, sizeof(type))]; 112 | } 113 | return type; 114 | } 115 | 116 | - (BOOL)isEqual:(id)object 117 | { 118 | return [self isEqualTo:object]; 119 | } 120 | 121 | - (BOOL)isEqualTo:(id)object 122 | { 123 | if(![object isKindOfClass:[self class]]) 124 | { 125 | return NO; 126 | } 127 | ANCSTransaction *transaction = (ANCSTransaction *)object; 128 | return [transaction.identifier isEqualTo:self.identifier]; 129 | } 130 | 131 | -(NSUInteger)hash 132 | { 133 | return [self.identifier hash]; 134 | } 135 | 136 | 137 | @end 138 | -------------------------------------------------------------------------------- /Mac ANCS/ANCSController.h: -------------------------------------------------------------------------------- 1 | // 2 | // JPANCSController.h 3 | // Mac ANCS 4 | // 5 | // Created by Jamie Pinkham on 9/20/13. 6 | // Copyright (c) 2013 Jamie Pinkham. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | 13 | typedef NS_OPTIONS(NSInteger, ANCSNotificationDetailsTypeMask) 14 | { 15 | ANCSNotificationDetailsTypeMaskAppIdentifier = (1 << 0), 16 | ANCSNotificationDetailsTypeMaskTitle = (1 << 1), 17 | ANCSNotificationDetailsTypeMaskSubtitle = (1 << 2), 18 | ANCSNotificationDetailsTypeMaskMessage = (1 << 3), 19 | ANCSNotificationDetailsTypeMaskMessageSize = (1 << 4), 20 | ANCSNotificationDetailsTypeMaskDate = (1 << 5), 21 | ANCSNotificationDetailsTypeMaskAll = ANCSNotificationDetailsTypeMaskAppIdentifier | 22 | ANCSNotificationDetailsTypeMaskTitle | 23 | ANCSNotificationDetailsTypeMaskSubtitle | 24 | ANCSNotificationDetailsTypeMaskMessage | 25 | ANCSNotificationDetailsTypeMaskMessageSize | 26 | ANCSNotificationDetailsTypeMaskDate, 27 | }; 28 | 29 | typedef NS_ENUM(uint8_t, ANCSNotificationAttributeType) 30 | { 31 | ANCSNotificationAttributeTypeAppIdentifier = 0, 32 | ANCSNotificationAttributeTypeTitle = 1, 33 | ANCSNotificationAttributeTypeSubtitle = 2, 34 | ANCSNotificationAttributeTypeMessage = 3, 35 | ANCSNotificationAttributeTypeMessageSize = 4, 36 | ANCSNotificationAttributeTypeDate = 5, 37 | ANCSNotificationAttributeTypeReserved = 6, 38 | }; 39 | 40 | typedef NS_ENUM(uint8_t, ANCSAppAttributeType) 41 | { 42 | ANCSAppAttributeTypeDisplayName = 0, 43 | }; 44 | 45 | 46 | @protocol ANCSControllerDelegate; 47 | @class ANCSNotification, ANCSNotificationCenter, ANCSNotificationDetails; 48 | 49 | @interface ANCSController : NSObject 50 | 51 | - (instancetype)initWithDelegate:(id)delegate queue:(dispatch_queue_t)queue; 52 | 53 | - (void)scanForNotificationCenters; 54 | - (void)stopScanning; 55 | - (void)connectToNotificationCenter:(ANCSNotificationCenter *)notificationCenter; 56 | - (void)getAttributesForNotification:(ANCSNotification *)notification detailsMask:(ANCSNotificationDetailsTypeMask)mask notificationCenter:(ANCSNotificationCenter *)notificationCenter; 57 | - (void)getApplicationNameForIdentifier:(NSString *)identifier onNotificationCenter:(ANCSNotificationCenter *)notificationCenter; 58 | 59 | @property (nonatomic, readonly, getter = isScanning) BOOL scanning; 60 | 61 | @property (nonatomic, weak) id delegate; 62 | 63 | @end 64 | 65 | @protocol ANCSControllerDelegate 66 | 67 | - (void)controllerStartedScanningForNotificationCenters:(ANCSController *)controller; 68 | - (void)controller:(ANCSController *)controller failedToStartScan:(NSError *)error; 69 | - (void)controller:(ANCSController *)controller foundNotificationCenter:(ANCSNotificationCenter *)notificationCenter; 70 | - (void)controller:(ANCSController *)controller connectedToNotificationCenter:(ANCSNotificationCenter *)notificationCenter; 71 | - (void)controller:(ANCSController *)controller failedToConnectToNotificationCenter:(ANCSNotificationCenter *)notificationCenter error:(NSError *)error; 72 | - (void)controller:(ANCSController *)controller disconnectedFromNotificationCenter:(ANCSNotificationCenter *)notificationCenter; 73 | - (void)controller:(ANCSController *)controller receivedNotification:(ANCSNotification *)notification notificationCenter:(ANCSNotificationCenter *)notificationCenter; 74 | - (void)controller:(ANCSController *)controller didUpdateNotificationDetails:(ANCSNotificationDetails *)notificationDetails notificationCenter:(ANCSNotificationCenter *)notificationCenter; 75 | 76 | - (void)controller:(ANCSController *)controller didRetrieveAppDisplayName:(NSString *)displayName forIdentifier:(NSString *)identifier; 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /Mac ANCS/ANCSNotificationDetailTransaction.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANCSNotificationDetailTransaction.m 3 | // Mac ANCS 4 | // 5 | // Created by Jamie Pinkham on 9/22/13. 6 | // Copyright (c) 2013 Jamie Pinkham. All rights reserved. 7 | // 8 | 9 | #import "ANCSNotificationDetailTransaction.h" 10 | #import "ANCSDetailTuple.h" 11 | #import "ANCSNotification.h" 12 | #import "ANCSNotificationDetails.h" 13 | 14 | static uint8_t const kANCSCommandIDGetNotificationAttributes = 0x0; 15 | static uint16_t const kANCSAttributeMaxLength = 0xffff; 16 | #define HEADER_SIZE 5 17 | 18 | @interface ANCSNotificationDetailTransaction () 19 | { 20 | NSDictionary *_tuples; 21 | } 22 | 23 | @property (nonatomic, assign) ANCSNotificationDetailsTypeMask mask; 24 | @property (nonatomic, readonly) ANCSNotification *notification; 25 | 26 | @end 27 | 28 | @implementation ANCSNotificationDetailTransaction 29 | 30 | - (instancetype)initWithNotification:(ANCSNotification *)note detailsMask:(ANCSNotificationDetailsTypeMask)mask; 31 | { 32 | self = [super init]; 33 | if (self) 34 | { 35 | _notification = note; 36 | _mask = mask; 37 | } 38 | return self; 39 | } 40 | 41 | - (NSDictionary *)tuples 42 | { 43 | if(_tuples == nil) 44 | { 45 | _tuples = [self buildTuples:self.mask]; 46 | } 47 | return _tuples; 48 | } 49 | 50 | #pragma mark - overrides 51 | 52 | - (NSInteger)headerLength 53 | { 54 | return HEADER_SIZE; 55 | } 56 | 57 | - (NSData *)buildCommandData 58 | { 59 | NSMutableData *data = [[NSMutableData alloc] init]; 60 | 61 | [data appendBytes:&kANCSCommandIDGetNotificationAttributes length:sizeof(kANCSCommandIDGetNotificationAttributes)]; 62 | 63 | uint32_t notificationId = (uint32_t)[self.notification eventId]; 64 | notificationId = CFSwapInt32HostToLittle(notificationId); 65 | [data appendBytes:¬ificationId length:sizeof(notificationId)]; 66 | 67 | NSArray *orderedTuples = [self orderedTuples]; 68 | for(ANCSDetailTuple *tuple in orderedTuples) 69 | { 70 | ANCSNotificationAttributeType type = tuple.attributeIdentifier; 71 | [data appendBytes:&type length:sizeof(ANCSNotificationAttributeType)]; 72 | 73 | if(type == ANCSNotificationAttributeTypeTitle || type == ANCSNotificationAttributeTypeSubtitle || type == ANCSNotificationAttributeTypeMessage) 74 | { 75 | [data appendBytes:&kANCSAttributeMaxLength length:sizeof(kANCSAttributeMaxLength)]; 76 | } 77 | } 78 | 79 | return [data copy]; 80 | } 81 | 82 | 83 | - (id)result 84 | { 85 | if(self.complete) 86 | { 87 | ANCSNotificationDetails *detail = [[ANCSNotificationDetails alloc] init]; 88 | uint32_t notificationId; 89 | [self.transactionData getBytes:¬ificationId range:NSMakeRange(1, sizeof(uint32_t))]; 90 | detail.notificationId = CFSwapInt32LittleToHost(notificationId); 91 | NSArray *allTuples = [self orderedTuples]; 92 | for (ANCSDetailTuple *tuple in allTuples) 93 | { 94 | switch (tuple.attributeIdentifier) { 95 | case ANCSNotificationAttributeTypeMessage: 96 | detail.message = [tuple value]; 97 | break; 98 | case ANCSNotificationAttributeTypeAppIdentifier: 99 | detail.appIdentifier = [tuple value]; 100 | break; 101 | case ANCSNotificationAttributeTypeDate: 102 | { 103 | NSString *dateString = [tuple value]; 104 | NSDate *date = [self.dateFormatter dateFromString:dateString]; 105 | detail.date = date; 106 | } 107 | break; 108 | case ANCSNotificationAttributeTypeMessageSize: 109 | detail.messageSize = [tuple value]; 110 | break; 111 | case ANCSNotificationAttributeTypeSubtitle: 112 | detail.subtitle = [tuple value]; 113 | break; 114 | case ANCSNotificationAttributeTypeTitle: 115 | detail.title = [tuple value]; 116 | break; 117 | default: 118 | break; 119 | } 120 | } 121 | 122 | return detail; 123 | } 124 | return nil; 125 | } 126 | 127 | #pragma mark - helpers 128 | 129 | - (NSArray *)orderedTuples 130 | { 131 | NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"attributeIdentifier" ascending:YES]; 132 | 133 | NSArray *orderedTuples = [[self.tuples allValues] sortedArrayUsingDescriptors:@[sort]]; 134 | 135 | return orderedTuples; 136 | } 137 | 138 | static NSDateFormatter *formatter = nil; 139 | - (NSDateFormatter *)dateFormatter 140 | { 141 | if(formatter == nil) 142 | { 143 | formatter = [[NSDateFormatter alloc] init]; 144 | [formatter setDateFormat:@"yyyyMMdd'T'HHmmSS"]; 145 | } 146 | return formatter; 147 | } 148 | 149 | - (NSDictionary *)buildTuples:(ANCSNotificationDetailsTypeMask)mask 150 | { 151 | NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; 152 | NSInteger type = ANCSNotificationAttributeTypeReserved; 153 | while(type >= 0) 154 | { 155 | if(mask & (1 << type)) 156 | { 157 | ANCSDetailTuple *tuple = [[ANCSDetailTuple alloc] init]; 158 | tuple.attributeIdentifier = type; 159 | dict[@(tuple.attributeIdentifier)] = tuple; 160 | } 161 | type--; 162 | } 163 | return [dict copy]; 164 | } 165 | 166 | @end 167 | -------------------------------------------------------------------------------- /Mac ANCS/ANCSController.m: -------------------------------------------------------------------------------- 1 | // 2 | // JPANCSController.m 3 | // Mac ANCS 4 | // 5 | // Created by Jamie Pinkham on 9/20/13. 6 | // Copyright (c) 2013 Jamie Pinkham. All rights reserved. 7 | // 8 | 9 | #import "ANCSController.h" 10 | #import "ANCSNotificationCenter.h" 11 | #import "ANCSNotification.h" 12 | #import "ANCSNotificationDetails.h" 13 | #import "ANCSNotificationDetailTransaction.h" 14 | #import "ANCSAppNameTransaction.h" 15 | 16 | static NSString * const kANCSServiceUUIDString = @"7905F431-B5CE-4E99-A40F-4B1E122D00D0"; 17 | static NSString * const kANCSNotificationSourceUUIDString = @"9FBF120D-6301-42D9-8C58-25E699A21DBD"; 18 | static NSString * const kANCSControlPointUUIDString = @"69D1D8F3-45E1-49A8-9821-9BBDFDAAD9D9"; 19 | static NSString * const kANCSDataSourceUUIDString = @"22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB"; 20 | 21 | @interface ANCSController () 22 | 23 | @property (nonatomic, strong) CBCentralManager *centralManager; 24 | @property (nonatomic, strong) dispatch_queue_t callbackQueue; 25 | @property (nonatomic, strong) dispatch_queue_t bluetoothQueue; 26 | @property (nonatomic, strong) CBUUID *serviceUUID; 27 | @property (nonatomic, strong) CBUUID *notificationSourceUUID; 28 | @property (nonatomic, strong) CBUUID *controlPointUUID; 29 | @property (nonatomic, strong) CBUUID *dataSourceUUID; 30 | @property (nonatomic, strong) NSMutableDictionary *ncsToPeripheral; 31 | @property (nonatomic, strong) NSMutableDictionary *peripheralsToNcs; 32 | 33 | @property (nonatomic, strong) CBCharacteristic *notificationSourceCharacterstic; 34 | @property (nonatomic, strong) CBCharacteristic *controlPointCharacteristic; 35 | @property (nonatomic, strong) CBCharacteristic *dataSourceCharacteristic; 36 | 37 | @property (nonatomic, strong) NSMutableDictionary *notifications; 38 | 39 | @property (nonatomic, strong) NSMutableDictionary *appIdentifiers; 40 | 41 | @property (nonatomic, strong) ANCSTransaction *currentTransaction; 42 | @property (nonatomic, strong) dispatch_semaphore_t transactionSemaphore; 43 | @property (nonatomic, strong) dispatch_semaphore_t timeoutSemaphore; 44 | @property (nonatomic, strong) dispatch_queue_t transactionQueue; 45 | 46 | @end 47 | 48 | @implementation ANCSController 49 | 50 | - (instancetype)initWithDelegate:(id)delegate queue:(dispatch_queue_t)queue 51 | { 52 | self = [super init]; 53 | if (self) 54 | { 55 | if(queue == NULL) 56 | { 57 | queue = dispatch_get_main_queue(); 58 | } 59 | _delegate = delegate; 60 | _callbackQueue = queue; 61 | _serviceUUID = [CBUUID UUIDWithString:kANCSServiceUUIDString]; 62 | _notificationSourceUUID = [CBUUID UUIDWithString:kANCSNotificationSourceUUIDString]; 63 | _controlPointUUID = [CBUUID UUIDWithString:kANCSControlPointUUIDString]; 64 | _dataSourceUUID = [CBUUID UUIDWithString:kANCSDataSourceUUIDString]; 65 | _ncsToPeripheral = [NSMutableDictionary new]; 66 | _peripheralsToNcs = [NSMutableDictionary new]; 67 | _notifications = [NSMutableDictionary new]; 68 | 69 | _transactionSemaphore = dispatch_semaphore_create(1); 70 | _transactionQueue = dispatch_queue_create("com.jamiepinkham.ancs_transaction_queue", DISPATCH_QUEUE_SERIAL); 71 | 72 | _timeoutSemaphore = dispatch_semaphore_create(0); 73 | 74 | } 75 | return self; 76 | } 77 | 78 | - (void)scanForNotificationCenters 79 | { 80 | self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:self.bluetoothQueue]; 81 | } 82 | 83 | - (void)stopScanning 84 | { 85 | _scanning = NO; 86 | [self.centralManager stopScan]; 87 | } 88 | 89 | 90 | - (void)connectToNotificationCenter:(ANCSNotificationCenter *)notificationCenter 91 | { 92 | CBPeripheral *peripheral = [self.ncsToPeripheral objectForKey:notificationCenter]; 93 | [self.centralManager connectPeripheral:peripheral options:nil]; 94 | } 95 | 96 | - (void)getAttributesForNotification:(ANCSNotification *)notification detailsMask:(ANCSNotificationDetailsTypeMask)mask notificationCenter:(ANCSNotificationCenter *)notificationCenter 97 | { 98 | NSLog(@"%@",NSStringFromSelector(_cmd)); 99 | ANCSNotification *localNote = [self.notifications objectForKey:@([notification eventId])]; 100 | if(localNote) 101 | { 102 | ANCSTransaction *transaction = [[ANCSNotificationDetailTransaction alloc] initWithNotification:localNote detailsMask:mask]; 103 | transaction.completionBlock = ^(id result, NSError *error){ 104 | if(result) 105 | { 106 | dispatch_async(self.callbackQueue, ^{ 107 | [self.delegate controller:self didUpdateNotificationDetails:result notificationCenter:notificationCenter]; 108 | 109 | }); 110 | } 111 | else 112 | { 113 | NSLog(@"retrive notification error = %@", error); 114 | } 115 | }; 116 | [self executeTransaction:transaction onNotificationCenter:notificationCenter]; 117 | 118 | } 119 | } 120 | 121 | - (void)getApplicationNameForIdentifier:(NSString *)identifier onNotificationCenter:(ANCSNotificationCenter *)notificationCenter 122 | { 123 | NSLog(@"%@",NSStringFromSelector(_cmd)); 124 | if(identifier == nil) 125 | { 126 | return; 127 | } 128 | if ([self.appIdentifiers objectForKey:identifier]) 129 | { 130 | dispatch_async(self.callbackQueue, ^{ 131 | NSString *displayName = [self.appIdentifiers objectForKey:identifier]; 132 | [self.delegate controller:self didRetrieveAppDisplayName:displayName forIdentifier:identifier]; 133 | }); 134 | } 135 | else 136 | { 137 | //currently broken, see: https://devforums.apple.com/message/876984#876984 138 | ANCSAppNameTransaction *transaction = [[ANCSAppNameTransaction alloc] initWithAppIdentifier:identifier]; 139 | transaction.completionBlock = ^(id result, NSError *error){ 140 | if(result) 141 | { 142 | self.appIdentifiers[identifier] = result; 143 | dispatch_async(self.callbackQueue, ^{ 144 | [self.delegate controller:self didRetrieveAppDisplayName:result forIdentifier:identifier]; 145 | }); 146 | } 147 | else 148 | { 149 | NSLog(@"retrive app name error = %@", error); 150 | } 151 | 152 | }; 153 | 154 | [self executeTransaction:transaction onNotificationCenter:notificationCenter]; 155 | } 156 | } 157 | 158 | 159 | - (void)centralManagerDidUpdateState:(CBCentralManager *)central 160 | { 161 | 162 | if(central.state == CBCentralManagerStateUnauthorized || central.state == CBCentralManagerStateUnsupported) 163 | { 164 | // [self handleFailToScan:nil]; 165 | } 166 | 167 | if(central.state != CBCentralManagerStatePoweredOn) 168 | { 169 | return; 170 | } 171 | 172 | [self.centralManager scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey : @NO}]; 173 | dispatch_async(self.callbackQueue, ^{ 174 | [self.delegate controllerStartedScanningForNotificationCenters:self]; 175 | }); 176 | } 177 | 178 | - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI 179 | { 180 | NSString *name = [peripheral name]; 181 | ANCSNotificationCenter *center = [[ANCSNotificationCenter alloc] init]; 182 | [center setUUID:peripheral.UUID]; 183 | [center setName:name]; 184 | [self.ncsToPeripheral setObject:peripheral forKey:center]; 185 | [self.peripheralsToNcs setObject:center forKey:CFBridgingRelease(CFUUIDCreateString(NULL, peripheral.UUID))]; 186 | 187 | dispatch_async(self.callbackQueue, ^{ 188 | [self.delegate controller:self foundNotificationCenter:center]; 189 | }); 190 | } 191 | 192 | - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral 193 | { 194 | [peripheral setDelegate:self]; 195 | [peripheral discoverServices:@[self.serviceUUID]]; 196 | } 197 | 198 | - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error 199 | { 200 | NSInteger idx = [[self.ncsToPeripheral allKeys] indexOfObject:peripheral]; 201 | if(idx != NSNotFound) 202 | { 203 | dispatch_async(self.callbackQueue, ^{ 204 | ANCSNotificationCenter *noteCenter = [self.ncsToPeripheral allKeys][idx]; 205 | [self.delegate controller:self disconnectedFromNotificationCenter:noteCenter]; 206 | }); 207 | } 208 | } 209 | 210 | - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error 211 | { 212 | NSInteger idx = [[self.ncsToPeripheral allKeys] indexOfObject:peripheral]; 213 | if(idx != NSNotFound) 214 | { 215 | dispatch_async(self.callbackQueue, ^{ 216 | ANCSNotificationCenter *noteCenter = [self.ncsToPeripheral allKeys][idx]; 217 | [self.delegate controller:self disconnectedFromNotificationCenter:noteCenter]; 218 | }); 219 | } 220 | } 221 | 222 | - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error 223 | { 224 | for(CBService *service in peripheral.services) 225 | { 226 | if([service.UUID isEqual:self.serviceUUID]) 227 | { 228 | [peripheral discoverCharacteristics:@[self.notificationSourceUUID, self.controlPointUUID, self.dataSourceUUID] forService:service]; 229 | } 230 | } 231 | } 232 | 233 | - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error 234 | { 235 | if([service.UUID isEqual:self.serviceUUID]) 236 | { 237 | for(CBCharacteristic *aChar in service.characteristics) 238 | { 239 | if([aChar.UUID isEqual:self.notificationSourceUUID]) 240 | { 241 | self.notificationSourceCharacterstic = aChar; 242 | [peripheral setNotifyValue:YES forCharacteristic:aChar]; 243 | } 244 | else if ([aChar.UUID isEqual:self.controlPointUUID]) 245 | { 246 | self.controlPointCharacteristic = aChar; 247 | } 248 | else if([aChar.UUID isEqual:self.dataSourceUUID]) 249 | { 250 | self.dataSourceCharacteristic = aChar; 251 | [peripheral setNotifyValue:YES forCharacteristic:aChar]; 252 | } 253 | } 254 | } 255 | } 256 | 257 | - (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error 258 | { 259 | if([characteristic.UUID isEqual:self.notificationSourceUUID]) 260 | { 261 | NSLog(@"notification source characteristic is notifying = %@", characteristic.isNotifying ? @"YES" : @"NO"); 262 | } 263 | if([characteristic.UUID isEqual:self.dataSourceUUID]) 264 | { 265 | NSLog(@"data source characteristic is notifying = %@", characteristic.isNotifying ? @"YES" : @"NO"); 266 | } 267 | 268 | } 269 | 270 | - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error 271 | { 272 | if([characteristic.UUID isEqual:self.notificationSourceUUID]) 273 | { 274 | ANCSNotification *notification = [[ANCSNotification alloc] initWithData:characteristic.value]; 275 | 276 | if(![self.notifications objectForKey:@([notification eventId])] && (notification.notificationType != ANCSEventNotificationTypeRemoved)) 277 | { 278 | [self.notifications setObject:notification forKey:@(notification.eventId)]; 279 | } 280 | else if([self.notifications objectForKey:@([notification eventId])] && (notification.notificationType == ANCSEventNotificationTypeRemoved)) 281 | { 282 | [self.notifications removeObjectForKey:@([notification eventId])]; 283 | } 284 | dispatch_async(self.callbackQueue, ^{ 285 | ANCSNotificationCenter *center = self.peripheralsToNcs[CFBridgingRelease(CFUUIDCreateString(NULL, peripheral.UUID))]; 286 | [self.delegate controller:self receivedNotification:notification notificationCenter:center]; 287 | }); 288 | } 289 | if([characteristic.UUID isEqual:self.dataSourceUUID]) 290 | { 291 | [self.currentTransaction appendData:characteristic.value]; 292 | if([self.currentTransaction isComplete]) 293 | { 294 | dispatch_semaphore_signal(self.timeoutSemaphore); 295 | } 296 | } 297 | } 298 | 299 | 300 | - (void)executeTransaction:(ANCSTransaction *)transaction onNotificationCenter:(ANCSNotificationCenter *)notificationCenter; 301 | { 302 | dispatch_async(self.transactionQueue, ^{ 303 | dispatch_semaphore_wait(self.transactionSemaphore, DISPATCH_TIME_FOREVER); 304 | CBPeripheral *peripheral = self.ncsToPeripheral[notificationCenter]; 305 | self.currentTransaction = transaction; 306 | NSData *packet = [transaction buildCommandData]; 307 | [peripheral writeValue:packet forCharacteristic:self.controlPointCharacteristic type:CBCharacteristicWriteWithResponse]; 308 | 309 | //THE TIMEOUT EXISTS BECAUSE OF THE FACT THAT THE GET APP NAME COMMAND IS BROKEN AS OF 9/23/12 310 | double timeoutInSeconds = 10.0; 311 | dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeoutInSeconds * NSEC_PER_SEC)); 312 | dispatch_semaphore_wait(self.timeoutSemaphore, timeout); 313 | 314 | transaction.completionBlock([transaction result], [transaction error]); 315 | self.currentTransaction = nil; 316 | 317 | dispatch_semaphore_signal(self.transactionSemaphore); 318 | }); 319 | } 320 | 321 | 322 | @end 323 | -------------------------------------------------------------------------------- /ANCS.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 502E62AC17ED20E900B0478C /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 502E62AB17ED20E900B0478C /* Cocoa.framework */; }; 11 | 502E62B617ED20E900B0478C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 502E62B417ED20E900B0478C /* InfoPlist.strings */; }; 12 | 502E62B817ED20E900B0478C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 502E62B717ED20E900B0478C /* main.m */; }; 13 | 502E62BC17ED20E900B0478C /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 502E62BA17ED20E900B0478C /* Credits.rtf */; }; 14 | 502E62BF17ED20E900B0478C /* JPANCSAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 502E62BE17ED20E900B0478C /* JPANCSAppDelegate.m */; }; 15 | 502E62C217ED20E900B0478C /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 502E62C017ED20E900B0478C /* MainMenu.xib */; }; 16 | 502E62C417ED20E900B0478C /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 502E62C317ED20E900B0478C /* Images.xcassets */; }; 17 | 502E62E017ED20F900B0478C /* IOBluetooth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 502E62DF17ED20F900B0478C /* IOBluetooth.framework */; }; 18 | 502E62E317ED211700B0478C /* ANCSController.m in Sources */ = {isa = PBXBuildFile; fileRef = 502E62E217ED211700B0478C /* ANCSController.m */; }; 19 | 502E62E617ED231600B0478C /* ANCSNotification.m in Sources */ = {isa = PBXBuildFile; fileRef = 502E62E517ED231600B0478C /* ANCSNotification.m */; }; 20 | 502E62E917ED25C400B0478C /* ANCSNotificationCenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 502E62E817ED25C400B0478C /* ANCSNotificationCenter.m */; }; 21 | 502E62EC17EE9CDB00B0478C /* ANCSNotificationDetails.m in Sources */ = {isa = PBXBuildFile; fileRef = 502E62EB17EE9CDB00B0478C /* ANCSNotificationDetails.m */; }; 22 | 502E62EF17EEA6D500B0478C /* ANCSNotificationDetailTransaction.m in Sources */ = {isa = PBXBuildFile; fileRef = 502E62EE17EEA6D500B0478C /* ANCSNotificationDetailTransaction.m */; }; 23 | 502E62F217EEA98400B0478C /* ANCSDetailTuple.m in Sources */ = {isa = PBXBuildFile; fileRef = 502E62F117EEA98400B0478C /* ANCSDetailTuple.m */; }; 24 | 502E62F517EFC51900B0478C /* ANCSTransaction.m in Sources */ = {isa = PBXBuildFile; fileRef = 502E62F417EFC51900B0478C /* ANCSTransaction.m */; }; 25 | 502E62F817EFE82400B0478C /* ANCSAppNameTransaction.m in Sources */ = {isa = PBXBuildFile; fileRef = 502E62F717EFE82400B0478C /* ANCSAppNameTransaction.m */; }; 26 | 502E62FF17EFF7FC00B0478C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 502E62FE17EFF7FC00B0478C /* Foundation.framework */; }; 27 | 502E630117EFF7FC00B0478C /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 502E630017EFF7FC00B0478C /* CoreGraphics.framework */; }; 28 | 502E630317EFF7FC00B0478C /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 502E630217EFF7FC00B0478C /* UIKit.framework */; }; 29 | 502E630917EFF7FC00B0478C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 502E630717EFF7FC00B0478C /* InfoPlist.strings */; }; 30 | 502E630B17EFF7FC00B0478C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 502E630A17EFF7FC00B0478C /* main.m */; }; 31 | 502E630F17EFF7FC00B0478C /* ANCSAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 502E630E17EFF7FC00B0478C /* ANCSAppDelegate.m */; }; 32 | 502E631217EFF7FC00B0478C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 502E631017EFF7FC00B0478C /* Main.storyboard */; }; 33 | 502E631517EFF7FC00B0478C /* ANCSViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 502E631417EFF7FC00B0478C /* ANCSViewController.m */; }; 34 | 502E631717EFF7FC00B0478C /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 502E631617EFF7FC00B0478C /* Images.xcassets */; }; 35 | 502E634117EFF89700B0478C /* CoreBluetooth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 502E634017EFF89700B0478C /* CoreBluetooth.framework */; }; 36 | /* End PBXBuildFile section */ 37 | 38 | /* Begin PBXFileReference section */ 39 | 502E62A817ED20E900B0478C /* ANCS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ANCS.app; sourceTree = BUILT_PRODUCTS_DIR; }; 40 | 502E62AB17ED20E900B0478C /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 41 | 502E62AE17ED20E900B0478C /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 42 | 502E62AF17ED20E900B0478C /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; 43 | 502E62B017ED20E900B0478C /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 44 | 502E62B317ED20E900B0478C /* ANCS-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ANCS-Info.plist"; sourceTree = ""; }; 45 | 502E62B517ED20E900B0478C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 46 | 502E62B717ED20E900B0478C /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 47 | 502E62B917ED20E900B0478C /* ANCS-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ANCS-Prefix.pch"; sourceTree = ""; }; 48 | 502E62BB17ED20E900B0478C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = ""; }; 49 | 502E62BD17ED20E900B0478C /* JPANCSAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JPANCSAppDelegate.h; sourceTree = ""; }; 50 | 502E62BE17ED20E900B0478C /* JPANCSAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JPANCSAppDelegate.m; sourceTree = ""; }; 51 | 502E62C117ED20E900B0478C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 52 | 502E62C317ED20E900B0478C /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 53 | 502E62CA17ED20EA00B0478C /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 54 | 502E62D117ED20EA00B0478C /* ANCSTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ANCSTests-Info.plist"; sourceTree = ""; }; 55 | 502E62D317ED20EA00B0478C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 56 | 502E62D517ED20EA00B0478C /* Mac_ANCSTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Mac_ANCSTests.m; sourceTree = ""; }; 57 | 502E62DF17ED20F900B0478C /* IOBluetooth.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOBluetooth.framework; path = System/Library/Frameworks/IOBluetooth.framework; sourceTree = SDKROOT; }; 58 | 502E62E117ED211700B0478C /* ANCSController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANCSController.h; sourceTree = ""; }; 59 | 502E62E217ED211700B0478C /* ANCSController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANCSController.m; sourceTree = ""; }; 60 | 502E62E417ED231600B0478C /* ANCSNotification.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANCSNotification.h; sourceTree = ""; }; 61 | 502E62E517ED231600B0478C /* ANCSNotification.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANCSNotification.m; sourceTree = ""; }; 62 | 502E62E717ED25C400B0478C /* ANCSNotificationCenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANCSNotificationCenter.h; sourceTree = ""; }; 63 | 502E62E817ED25C400B0478C /* ANCSNotificationCenter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANCSNotificationCenter.m; sourceTree = ""; }; 64 | 502E62EA17EE9CDB00B0478C /* ANCSNotificationDetails.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANCSNotificationDetails.h; sourceTree = ""; }; 65 | 502E62EB17EE9CDB00B0478C /* ANCSNotificationDetails.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANCSNotificationDetails.m; sourceTree = ""; }; 66 | 502E62ED17EEA6D500B0478C /* ANCSNotificationDetailTransaction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANCSNotificationDetailTransaction.h; sourceTree = ""; }; 67 | 502E62EE17EEA6D500B0478C /* ANCSNotificationDetailTransaction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANCSNotificationDetailTransaction.m; sourceTree = ""; }; 68 | 502E62F017EEA98400B0478C /* ANCSDetailTuple.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANCSDetailTuple.h; sourceTree = ""; }; 69 | 502E62F117EEA98400B0478C /* ANCSDetailTuple.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANCSDetailTuple.m; sourceTree = ""; }; 70 | 502E62F317EFC51900B0478C /* ANCSTransaction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANCSTransaction.h; sourceTree = ""; }; 71 | 502E62F417EFC51900B0478C /* ANCSTransaction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANCSTransaction.m; sourceTree = ""; }; 72 | 502E62F617EFE82400B0478C /* ANCSAppNameTransaction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANCSAppNameTransaction.h; sourceTree = ""; }; 73 | 502E62F717EFE82400B0478C /* ANCSAppNameTransaction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANCSAppNameTransaction.m; sourceTree = ""; }; 74 | 502E62FD17EFF7FC00B0478C /* ANCS iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ANCS iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 75 | 502E62FE17EFF7FC00B0478C /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 76 | 502E630017EFF7FC00B0478C /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 77 | 502E630217EFF7FC00B0478C /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; 78 | 502E630617EFF7FC00B0478C /* ANCS iOS-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ANCS iOS-Info.plist"; sourceTree = ""; }; 79 | 502E630817EFF7FC00B0478C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 80 | 502E630A17EFF7FC00B0478C /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 81 | 502E630C17EFF7FC00B0478C /* ANCS iOS-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ANCS iOS-Prefix.pch"; sourceTree = ""; }; 82 | 502E630D17EFF7FC00B0478C /* ANCSAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ANCSAppDelegate.h; sourceTree = ""; }; 83 | 502E630E17EFF7FC00B0478C /* ANCSAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ANCSAppDelegate.m; sourceTree = ""; }; 84 | 502E631117EFF7FC00B0478C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 85 | 502E631317EFF7FC00B0478C /* ANCSViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ANCSViewController.h; sourceTree = ""; }; 86 | 502E631417EFF7FC00B0478C /* ANCSViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ANCSViewController.m; sourceTree = ""; }; 87 | 502E631617EFF7FC00B0478C /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 88 | 502E632417EFF7FC00B0478C /* ANCS iOSTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ANCS iOSTests-Info.plist"; sourceTree = ""; }; 89 | 502E632617EFF7FC00B0478C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 90 | 502E632817EFF7FC00B0478C /* ANCS_iOSTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ANCS_iOSTests.m; sourceTree = ""; }; 91 | 502E634017EFF89700B0478C /* CoreBluetooth.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreBluetooth.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.0.sdk/System/Library/Frameworks/CoreBluetooth.framework; sourceTree = DEVELOPER_DIR; }; 92 | /* End PBXFileReference section */ 93 | 94 | /* Begin PBXFrameworksBuildPhase section */ 95 | 502E62A517ED20E900B0478C /* Frameworks */ = { 96 | isa = PBXFrameworksBuildPhase; 97 | buildActionMask = 2147483647; 98 | files = ( 99 | 502E62E017ED20F900B0478C /* IOBluetooth.framework in Frameworks */, 100 | 502E62AC17ED20E900B0478C /* Cocoa.framework in Frameworks */, 101 | ); 102 | runOnlyForDeploymentPostprocessing = 0; 103 | }; 104 | 502E62FA17EFF7FC00B0478C /* Frameworks */ = { 105 | isa = PBXFrameworksBuildPhase; 106 | buildActionMask = 2147483647; 107 | files = ( 108 | 502E634117EFF89700B0478C /* CoreBluetooth.framework in Frameworks */, 109 | 502E630117EFF7FC00B0478C /* CoreGraphics.framework in Frameworks */, 110 | 502E630317EFF7FC00B0478C /* UIKit.framework in Frameworks */, 111 | 502E62FF17EFF7FC00B0478C /* Foundation.framework in Frameworks */, 112 | ); 113 | runOnlyForDeploymentPostprocessing = 0; 114 | }; 115 | /* End PBXFrameworksBuildPhase section */ 116 | 117 | /* Begin PBXGroup section */ 118 | 502E629F17ED20E900B0478C = { 119 | isa = PBXGroup; 120 | children = ( 121 | 502E62B117ED20E900B0478C /* Mac ANCS */, 122 | 502E62CF17ED20EA00B0478C /* Mac ANCSTests */, 123 | 502E630417EFF7FC00B0478C /* ANCS iOS */, 124 | 502E632217EFF7FC00B0478C /* ANCS iOSTests */, 125 | 502E62AA17ED20E900B0478C /* Frameworks */, 126 | 502E62A917ED20E900B0478C /* Products */, 127 | ); 128 | sourceTree = ""; 129 | }; 130 | 502E62A917ED20E900B0478C /* Products */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | 502E62A817ED20E900B0478C /* ANCS.app */, 134 | 502E62FD17EFF7FC00B0478C /* ANCS iOS.app */, 135 | ); 136 | name = Products; 137 | sourceTree = ""; 138 | }; 139 | 502E62AA17ED20E900B0478C /* Frameworks */ = { 140 | isa = PBXGroup; 141 | children = ( 142 | 502E634017EFF89700B0478C /* CoreBluetooth.framework */, 143 | 502E62DF17ED20F900B0478C /* IOBluetooth.framework */, 144 | 502E62AB17ED20E900B0478C /* Cocoa.framework */, 145 | 502E62CA17ED20EA00B0478C /* XCTest.framework */, 146 | 502E62FE17EFF7FC00B0478C /* Foundation.framework */, 147 | 502E630017EFF7FC00B0478C /* CoreGraphics.framework */, 148 | 502E630217EFF7FC00B0478C /* UIKit.framework */, 149 | 502E62AD17ED20E900B0478C /* Other Frameworks */, 150 | ); 151 | name = Frameworks; 152 | sourceTree = ""; 153 | }; 154 | 502E62AD17ED20E900B0478C /* Other Frameworks */ = { 155 | isa = PBXGroup; 156 | children = ( 157 | 502E62AE17ED20E900B0478C /* AppKit.framework */, 158 | 502E62AF17ED20E900B0478C /* CoreData.framework */, 159 | 502E62B017ED20E900B0478C /* Foundation.framework */, 160 | ); 161 | name = "Other Frameworks"; 162 | sourceTree = ""; 163 | }; 164 | 502E62B117ED20E900B0478C /* Mac ANCS */ = { 165 | isa = PBXGroup; 166 | children = ( 167 | 502E62BD17ED20E900B0478C /* JPANCSAppDelegate.h */, 168 | 502E62BE17ED20E900B0478C /* JPANCSAppDelegate.m */, 169 | 502E62C017ED20E900B0478C /* MainMenu.xib */, 170 | 502E62C317ED20E900B0478C /* Images.xcassets */, 171 | 502E62B217ED20E900B0478C /* Supporting Files */, 172 | 502E62E117ED211700B0478C /* ANCSController.h */, 173 | 502E62E217ED211700B0478C /* ANCSController.m */, 174 | 502E62E417ED231600B0478C /* ANCSNotification.h */, 175 | 502E62E517ED231600B0478C /* ANCSNotification.m */, 176 | 502E62EA17EE9CDB00B0478C /* ANCSNotificationDetails.h */, 177 | 502E62EB17EE9CDB00B0478C /* ANCSNotificationDetails.m */, 178 | 502E62E717ED25C400B0478C /* ANCSNotificationCenter.h */, 179 | 502E62E817ED25C400B0478C /* ANCSNotificationCenter.m */, 180 | 502E62F317EFC51900B0478C /* ANCSTransaction.h */, 181 | 502E62F417EFC51900B0478C /* ANCSTransaction.m */, 182 | 502E62F617EFE82400B0478C /* ANCSAppNameTransaction.h */, 183 | 502E62F717EFE82400B0478C /* ANCSAppNameTransaction.m */, 184 | 502E62ED17EEA6D500B0478C /* ANCSNotificationDetailTransaction.h */, 185 | 502E62EE17EEA6D500B0478C /* ANCSNotificationDetailTransaction.m */, 186 | 502E62F017EEA98400B0478C /* ANCSDetailTuple.h */, 187 | 502E62F117EEA98400B0478C /* ANCSDetailTuple.m */, 188 | ); 189 | path = "Mac ANCS"; 190 | sourceTree = ""; 191 | }; 192 | 502E62B217ED20E900B0478C /* Supporting Files */ = { 193 | isa = PBXGroup; 194 | children = ( 195 | 502E62B317ED20E900B0478C /* ANCS-Info.plist */, 196 | 502E62B417ED20E900B0478C /* InfoPlist.strings */, 197 | 502E62B717ED20E900B0478C /* main.m */, 198 | 502E62B917ED20E900B0478C /* ANCS-Prefix.pch */, 199 | 502E62BA17ED20E900B0478C /* Credits.rtf */, 200 | ); 201 | name = "Supporting Files"; 202 | sourceTree = ""; 203 | }; 204 | 502E62CF17ED20EA00B0478C /* Mac ANCSTests */ = { 205 | isa = PBXGroup; 206 | children = ( 207 | 502E62D517ED20EA00B0478C /* Mac_ANCSTests.m */, 208 | 502E62D017ED20EA00B0478C /* Supporting Files */, 209 | ); 210 | path = "Mac ANCSTests"; 211 | sourceTree = ""; 212 | }; 213 | 502E62D017ED20EA00B0478C /* Supporting Files */ = { 214 | isa = PBXGroup; 215 | children = ( 216 | 502E62D117ED20EA00B0478C /* ANCSTests-Info.plist */, 217 | 502E62D217ED20EA00B0478C /* InfoPlist.strings */, 218 | ); 219 | name = "Supporting Files"; 220 | sourceTree = ""; 221 | }; 222 | 502E630417EFF7FC00B0478C /* ANCS iOS */ = { 223 | isa = PBXGroup; 224 | children = ( 225 | 502E630D17EFF7FC00B0478C /* ANCSAppDelegate.h */, 226 | 502E630E17EFF7FC00B0478C /* ANCSAppDelegate.m */, 227 | 502E631017EFF7FC00B0478C /* Main.storyboard */, 228 | 502E631317EFF7FC00B0478C /* ANCSViewController.h */, 229 | 502E631417EFF7FC00B0478C /* ANCSViewController.m */, 230 | 502E631617EFF7FC00B0478C /* Images.xcassets */, 231 | 502E630517EFF7FC00B0478C /* Supporting Files */, 232 | ); 233 | path = "ANCS iOS"; 234 | sourceTree = ""; 235 | }; 236 | 502E630517EFF7FC00B0478C /* Supporting Files */ = { 237 | isa = PBXGroup; 238 | children = ( 239 | 502E630617EFF7FC00B0478C /* ANCS iOS-Info.plist */, 240 | 502E630717EFF7FC00B0478C /* InfoPlist.strings */, 241 | 502E630A17EFF7FC00B0478C /* main.m */, 242 | 502E630C17EFF7FC00B0478C /* ANCS iOS-Prefix.pch */, 243 | ); 244 | name = "Supporting Files"; 245 | sourceTree = ""; 246 | }; 247 | 502E632217EFF7FC00B0478C /* ANCS iOSTests */ = { 248 | isa = PBXGroup; 249 | children = ( 250 | 502E632817EFF7FC00B0478C /* ANCS_iOSTests.m */, 251 | 502E632317EFF7FC00B0478C /* Supporting Files */, 252 | ); 253 | path = "ANCS iOSTests"; 254 | sourceTree = ""; 255 | }; 256 | 502E632317EFF7FC00B0478C /* Supporting Files */ = { 257 | isa = PBXGroup; 258 | children = ( 259 | 502E632417EFF7FC00B0478C /* ANCS iOSTests-Info.plist */, 260 | 502E632517EFF7FC00B0478C /* InfoPlist.strings */, 261 | ); 262 | name = "Supporting Files"; 263 | sourceTree = ""; 264 | }; 265 | /* End PBXGroup section */ 266 | 267 | /* Begin PBXNativeTarget section */ 268 | 502E62A717ED20E900B0478C /* ANCS */ = { 269 | isa = PBXNativeTarget; 270 | buildConfigurationList = 502E62D917ED20EA00B0478C /* Build configuration list for PBXNativeTarget "ANCS" */; 271 | buildPhases = ( 272 | 502E62A417ED20E900B0478C /* Sources */, 273 | 502E62A517ED20E900B0478C /* Frameworks */, 274 | 502E62A617ED20E900B0478C /* Resources */, 275 | ); 276 | buildRules = ( 277 | ); 278 | dependencies = ( 279 | ); 280 | name = ANCS; 281 | productName = "Mac ANCS"; 282 | productReference = 502E62A817ED20E900B0478C /* ANCS.app */; 283 | productType = "com.apple.product-type.application"; 284 | }; 285 | 502E62FC17EFF7FC00B0478C /* ANCS iOS */ = { 286 | isa = PBXNativeTarget; 287 | buildConfigurationList = 502E632A17EFF7FC00B0478C /* Build configuration list for PBXNativeTarget "ANCS iOS" */; 288 | buildPhases = ( 289 | 502E62F917EFF7FC00B0478C /* Sources */, 290 | 502E62FA17EFF7FC00B0478C /* Frameworks */, 291 | 502E62FB17EFF7FC00B0478C /* Resources */, 292 | ); 293 | buildRules = ( 294 | ); 295 | dependencies = ( 296 | ); 297 | name = "ANCS iOS"; 298 | productName = "ANCS iOS"; 299 | productReference = 502E62FD17EFF7FC00B0478C /* ANCS iOS.app */; 300 | productType = "com.apple.product-type.application"; 301 | }; 302 | /* End PBXNativeTarget section */ 303 | 304 | /* Begin PBXProject section */ 305 | 502E62A017ED20E900B0478C /* Project object */ = { 306 | isa = PBXProject; 307 | attributes = { 308 | CLASSPREFIX = JPANCS; 309 | LastUpgradeCheck = 0500; 310 | ORGANIZATIONNAME = "Jamie Pinkham"; 311 | }; 312 | buildConfigurationList = 502E62A317ED20E900B0478C /* Build configuration list for PBXProject "ANCS" */; 313 | compatibilityVersion = "Xcode 3.2"; 314 | developmentRegion = English; 315 | hasScannedForEncodings = 0; 316 | knownRegions = ( 317 | en, 318 | Base, 319 | ); 320 | mainGroup = 502E629F17ED20E900B0478C; 321 | productRefGroup = 502E62A917ED20E900B0478C /* Products */; 322 | projectDirPath = ""; 323 | projectRoot = ""; 324 | targets = ( 325 | 502E62A717ED20E900B0478C /* ANCS */, 326 | 502E62FC17EFF7FC00B0478C /* ANCS iOS */, 327 | ); 328 | }; 329 | /* End PBXProject section */ 330 | 331 | /* Begin PBXResourcesBuildPhase section */ 332 | 502E62A617ED20E900B0478C /* Resources */ = { 333 | isa = PBXResourcesBuildPhase; 334 | buildActionMask = 2147483647; 335 | files = ( 336 | 502E62B617ED20E900B0478C /* InfoPlist.strings in Resources */, 337 | 502E62C417ED20E900B0478C /* Images.xcassets in Resources */, 338 | 502E62BC17ED20E900B0478C /* Credits.rtf in Resources */, 339 | 502E62C217ED20E900B0478C /* MainMenu.xib in Resources */, 340 | ); 341 | runOnlyForDeploymentPostprocessing = 0; 342 | }; 343 | 502E62FB17EFF7FC00B0478C /* Resources */ = { 344 | isa = PBXResourcesBuildPhase; 345 | buildActionMask = 2147483647; 346 | files = ( 347 | 502E631717EFF7FC00B0478C /* Images.xcassets in Resources */, 348 | 502E630917EFF7FC00B0478C /* InfoPlist.strings in Resources */, 349 | 502E631217EFF7FC00B0478C /* Main.storyboard in Resources */, 350 | ); 351 | runOnlyForDeploymentPostprocessing = 0; 352 | }; 353 | /* End PBXResourcesBuildPhase section */ 354 | 355 | /* Begin PBXSourcesBuildPhase section */ 356 | 502E62A417ED20E900B0478C /* Sources */ = { 357 | isa = PBXSourcesBuildPhase; 358 | buildActionMask = 2147483647; 359 | files = ( 360 | 502E62E617ED231600B0478C /* ANCSNotification.m in Sources */, 361 | 502E62F217EEA98400B0478C /* ANCSDetailTuple.m in Sources */, 362 | 502E62F817EFE82400B0478C /* ANCSAppNameTransaction.m in Sources */, 363 | 502E62B817ED20E900B0478C /* main.m in Sources */, 364 | 502E62EC17EE9CDB00B0478C /* ANCSNotificationDetails.m in Sources */, 365 | 502E62F517EFC51900B0478C /* ANCSTransaction.m in Sources */, 366 | 502E62E917ED25C400B0478C /* ANCSNotificationCenter.m in Sources */, 367 | 502E62EF17EEA6D500B0478C /* ANCSNotificationDetailTransaction.m in Sources */, 368 | 502E62E317ED211700B0478C /* ANCSController.m in Sources */, 369 | 502E62BF17ED20E900B0478C /* JPANCSAppDelegate.m in Sources */, 370 | ); 371 | runOnlyForDeploymentPostprocessing = 0; 372 | }; 373 | 502E62F917EFF7FC00B0478C /* Sources */ = { 374 | isa = PBXSourcesBuildPhase; 375 | buildActionMask = 2147483647; 376 | files = ( 377 | 502E630B17EFF7FC00B0478C /* main.m in Sources */, 378 | 502E631517EFF7FC00B0478C /* ANCSViewController.m in Sources */, 379 | 502E630F17EFF7FC00B0478C /* ANCSAppDelegate.m in Sources */, 380 | ); 381 | runOnlyForDeploymentPostprocessing = 0; 382 | }; 383 | /* End PBXSourcesBuildPhase section */ 384 | 385 | /* Begin PBXVariantGroup section */ 386 | 502E62B417ED20E900B0478C /* InfoPlist.strings */ = { 387 | isa = PBXVariantGroup; 388 | children = ( 389 | 502E62B517ED20E900B0478C /* en */, 390 | ); 391 | name = InfoPlist.strings; 392 | sourceTree = ""; 393 | }; 394 | 502E62BA17ED20E900B0478C /* Credits.rtf */ = { 395 | isa = PBXVariantGroup; 396 | children = ( 397 | 502E62BB17ED20E900B0478C /* en */, 398 | ); 399 | name = Credits.rtf; 400 | sourceTree = ""; 401 | }; 402 | 502E62C017ED20E900B0478C /* MainMenu.xib */ = { 403 | isa = PBXVariantGroup; 404 | children = ( 405 | 502E62C117ED20E900B0478C /* Base */, 406 | ); 407 | name = MainMenu.xib; 408 | sourceTree = ""; 409 | }; 410 | 502E62D217ED20EA00B0478C /* InfoPlist.strings */ = { 411 | isa = PBXVariantGroup; 412 | children = ( 413 | 502E62D317ED20EA00B0478C /* en */, 414 | ); 415 | name = InfoPlist.strings; 416 | sourceTree = ""; 417 | }; 418 | 502E630717EFF7FC00B0478C /* InfoPlist.strings */ = { 419 | isa = PBXVariantGroup; 420 | children = ( 421 | 502E630817EFF7FC00B0478C /* en */, 422 | ); 423 | name = InfoPlist.strings; 424 | sourceTree = ""; 425 | }; 426 | 502E631017EFF7FC00B0478C /* Main.storyboard */ = { 427 | isa = PBXVariantGroup; 428 | children = ( 429 | 502E631117EFF7FC00B0478C /* Base */, 430 | ); 431 | name = Main.storyboard; 432 | sourceTree = ""; 433 | }; 434 | 502E632517EFF7FC00B0478C /* InfoPlist.strings */ = { 435 | isa = PBXVariantGroup; 436 | children = ( 437 | 502E632617EFF7FC00B0478C /* en */, 438 | ); 439 | name = InfoPlist.strings; 440 | sourceTree = ""; 441 | }; 442 | /* End PBXVariantGroup section */ 443 | 444 | /* Begin XCBuildConfiguration section */ 445 | 502E62D717ED20EA00B0478C /* Debug */ = { 446 | isa = XCBuildConfiguration; 447 | buildSettings = { 448 | ALWAYS_SEARCH_USER_PATHS = NO; 449 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 450 | CLANG_CXX_LIBRARY = "libc++"; 451 | CLANG_ENABLE_OBJC_ARC = YES; 452 | CLANG_WARN_BOOL_CONVERSION = YES; 453 | CLANG_WARN_CONSTANT_CONVERSION = YES; 454 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 455 | CLANG_WARN_EMPTY_BODY = YES; 456 | CLANG_WARN_ENUM_CONVERSION = YES; 457 | CLANG_WARN_INT_CONVERSION = YES; 458 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 459 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 460 | COPY_PHASE_STRIP = NO; 461 | GCC_C_LANGUAGE_STANDARD = gnu99; 462 | GCC_DYNAMIC_NO_PIC = NO; 463 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 464 | GCC_OPTIMIZATION_LEVEL = 0; 465 | GCC_PREPROCESSOR_DEFINITIONS = ( 466 | "DEBUG=1", 467 | "$(inherited)", 468 | ); 469 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 470 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 471 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 472 | GCC_WARN_UNDECLARED_SELECTOR = YES; 473 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 474 | GCC_WARN_UNUSED_FUNCTION = YES; 475 | GCC_WARN_UNUSED_VARIABLE = YES; 476 | MACOSX_DEPLOYMENT_TARGET = 10.8; 477 | ONLY_ACTIVE_ARCH = YES; 478 | SDKROOT = macosx; 479 | }; 480 | name = Debug; 481 | }; 482 | 502E62D817ED20EA00B0478C /* Release */ = { 483 | isa = XCBuildConfiguration; 484 | buildSettings = { 485 | ALWAYS_SEARCH_USER_PATHS = NO; 486 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 487 | CLANG_CXX_LIBRARY = "libc++"; 488 | CLANG_ENABLE_OBJC_ARC = YES; 489 | CLANG_WARN_BOOL_CONVERSION = YES; 490 | CLANG_WARN_CONSTANT_CONVERSION = YES; 491 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 492 | CLANG_WARN_EMPTY_BODY = YES; 493 | CLANG_WARN_ENUM_CONVERSION = YES; 494 | CLANG_WARN_INT_CONVERSION = YES; 495 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 496 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 497 | COPY_PHASE_STRIP = YES; 498 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 499 | ENABLE_NS_ASSERTIONS = NO; 500 | GCC_C_LANGUAGE_STANDARD = gnu99; 501 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 502 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 503 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 504 | GCC_WARN_UNDECLARED_SELECTOR = YES; 505 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 506 | GCC_WARN_UNUSED_FUNCTION = YES; 507 | GCC_WARN_UNUSED_VARIABLE = YES; 508 | MACOSX_DEPLOYMENT_TARGET = 10.8; 509 | SDKROOT = macosx; 510 | }; 511 | name = Release; 512 | }; 513 | 502E62DA17ED20EA00B0478C /* Debug */ = { 514 | isa = XCBuildConfiguration; 515 | buildSettings = { 516 | ARCHS = "$(ARCHS_STANDARD)"; 517 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 518 | COMBINE_HIDPI_IMAGES = YES; 519 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 520 | GCC_PREFIX_HEADER = "Mac ANCS/ANCS-Prefix.pch"; 521 | INFOPLIST_FILE = "Mac ANCS/ANCS-Info.plist"; 522 | ONLY_ACTIVE_ARCH = YES; 523 | PRODUCT_NAME = ANCS; 524 | WRAPPER_EXTENSION = app; 525 | }; 526 | name = Debug; 527 | }; 528 | 502E62DB17ED20EA00B0478C /* Release */ = { 529 | isa = XCBuildConfiguration; 530 | buildSettings = { 531 | ARCHS = "$(ARCHS_STANDARD)"; 532 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 533 | COMBINE_HIDPI_IMAGES = YES; 534 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 535 | GCC_PREFIX_HEADER = "Mac ANCS/ANCS-Prefix.pch"; 536 | INFOPLIST_FILE = "Mac ANCS/ANCS-Info.plist"; 537 | ONLY_ACTIVE_ARCH = YES; 538 | PRODUCT_NAME = ANCS; 539 | WRAPPER_EXTENSION = app; 540 | }; 541 | name = Release; 542 | }; 543 | 502E632B17EFF7FC00B0478C /* Debug */ = { 544 | isa = XCBuildConfiguration; 545 | buildSettings = { 546 | ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; 547 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 548 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 549 | CLANG_ENABLE_MODULES = YES; 550 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 551 | FRAMEWORK_SEARCH_PATHS = ( 552 | "$(inherited)", 553 | "$(DEVELOPER_FRAMEWORKS_DIR)", 554 | ); 555 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 556 | GCC_PREFIX_HEADER = "ANCS iOS/ANCS iOS-Prefix.pch"; 557 | GCC_PREPROCESSOR_DEFINITIONS = ( 558 | "DEBUG=1", 559 | "$(inherited)", 560 | ); 561 | INFOPLIST_FILE = "ANCS iOS/ANCS iOS-Info.plist"; 562 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 563 | PRODUCT_NAME = "$(TARGET_NAME)"; 564 | SDKROOT = iphoneos; 565 | WRAPPER_EXTENSION = app; 566 | }; 567 | name = Debug; 568 | }; 569 | 502E632C17EFF7FC00B0478C /* Release */ = { 570 | isa = XCBuildConfiguration; 571 | buildSettings = { 572 | ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; 573 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 574 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 575 | CLANG_ENABLE_MODULES = YES; 576 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 577 | FRAMEWORK_SEARCH_PATHS = ( 578 | "$(inherited)", 579 | "$(DEVELOPER_FRAMEWORKS_DIR)", 580 | ); 581 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 582 | GCC_PREFIX_HEADER = "ANCS iOS/ANCS iOS-Prefix.pch"; 583 | INFOPLIST_FILE = "ANCS iOS/ANCS iOS-Info.plist"; 584 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 585 | PRODUCT_NAME = "$(TARGET_NAME)"; 586 | SDKROOT = iphoneos; 587 | VALIDATE_PRODUCT = YES; 588 | WRAPPER_EXTENSION = app; 589 | }; 590 | name = Release; 591 | }; 592 | /* End XCBuildConfiguration section */ 593 | 594 | /* Begin XCConfigurationList section */ 595 | 502E62A317ED20E900B0478C /* Build configuration list for PBXProject "ANCS" */ = { 596 | isa = XCConfigurationList; 597 | buildConfigurations = ( 598 | 502E62D717ED20EA00B0478C /* Debug */, 599 | 502E62D817ED20EA00B0478C /* Release */, 600 | ); 601 | defaultConfigurationIsVisible = 0; 602 | defaultConfigurationName = Release; 603 | }; 604 | 502E62D917ED20EA00B0478C /* Build configuration list for PBXNativeTarget "ANCS" */ = { 605 | isa = XCConfigurationList; 606 | buildConfigurations = ( 607 | 502E62DA17ED20EA00B0478C /* Debug */, 608 | 502E62DB17ED20EA00B0478C /* Release */, 609 | ); 610 | defaultConfigurationIsVisible = 0; 611 | defaultConfigurationName = Release; 612 | }; 613 | 502E632A17EFF7FC00B0478C /* Build configuration list for PBXNativeTarget "ANCS iOS" */ = { 614 | isa = XCConfigurationList; 615 | buildConfigurations = ( 616 | 502E632B17EFF7FC00B0478C /* Debug */, 617 | 502E632C17EFF7FC00B0478C /* Release */, 618 | ); 619 | defaultConfigurationIsVisible = 0; 620 | defaultConfigurationName = Release; 621 | }; 622 | /* End XCConfigurationList section */ 623 | }; 624 | rootObject = 502E62A017ED20E900B0478C /* Project object */; 625 | } 626 | -------------------------------------------------------------------------------- /Mac ANCS/Base.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | Default 522 | 523 | 524 | 525 | 526 | 527 | 528 | Left to Right 529 | 530 | 531 | 532 | 533 | 534 | 535 | Right to Left 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | Default 547 | 548 | 549 | 550 | 551 | 552 | 553 | Left to Right 554 | 555 | 556 | 557 | 558 | 559 | 560 | Right to Left 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | --------------------------------------------------------------------------------