Added beep. Settable sound file location via widget property. Client app sets this.
[zxing.git] / iphone / ZXingWidget / ZXingWidgetController.m
1 /**
2  * Copyright 2009 Jeff Verkoeyen
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *    http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #import "ZXingWidgetController.h"
18 #import "Decoder.h"
19 #import "NSString+HTML.h"
20 #import "ResultParser.h"
21 #import "ParsedResult.h"
22 #import "ResultAction.h"
23 #include <sys/types.h>
24 #include <sys/sysctl.h>
25
26 #define CAMERA_SCALAR 1.12412 // scalar = (480 / (2048 / 480))
27 #define FIRST_TAKE_DELAY 1.0
28
29 CGImageRef UIGetScreenImage();
30
31 @implementation ZXingWidgetController
32 @synthesize result, actions, showCancel, delegate, soundToPlay;
33
34 - (id)initWithDelegate:(id<ZXingDelegate>)scanDelegate {
35         if (self = [super init]) {
36                 [self setDelegate:scanDelegate];
37                 showCancel = true;
38                 beepSound = -1;
39                 self.wantsFullScreenLayout = YES;
40                 self.sourceType = UIImagePickerControllerSourceTypeCamera;
41                 float zoomFactor = CAMERA_SCALAR;
42                 if ([self fixedFocus]) {
43                         zoomFactor *= 1.5;
44                 }
45                 self.cameraViewTransform = CGAffineTransformScale(
46                                         self.cameraViewTransform, zoomFactor, zoomFactor);
47                 overlayView = [[OverlayView alloc] initWithCancelEnabled:showCancel frame:[UIScreen mainScreen].bounds];
48                 [overlayView setDelegate:self];
49                 self.sourceType = UIImagePickerControllerSourceTypeCamera;
50                 self.showsCameraControls = NO;
51                 self.cameraOverlayView = overlayView;
52                 self.allowsEditing = NO; // [[NSUserDefaults standardUserDefaults] boolForKey:@"allowEditing"];
53         }
54         
55         return self;
56 }
57
58 - (void)dealloc {
59         if (beepSound != -1) {
60                 AudioServicesDisposeSystemSoundID(beepSound);
61         }
62         [overlayView dealloc];
63         [super dealloc];
64 }
65
66 - (void)cancelled {
67         NSLog(@"cancelled called in ZXingWidgetController");
68         wasCancelled = true;
69         if (delegate != nil) {
70                 [delegate cancelled];
71         }
72 }
73
74 - (NSString *)getPlatform {
75         size_t size;
76     sysctlbyname("hw.machine", NULL, &size, NULL, 0);
77     char *machine = malloc(size);
78     sysctlbyname("hw.machine", machine, &size, NULL, 0);
79     NSString *platform = [NSString stringWithCString:machine encoding:NSASCIIStringEncoding];
80     free(machine);
81         return platform;
82 }
83
84 - (BOOL)fixedFocus {
85         NSString *platform = [self getPlatform];
86         if ([platform isEqualToString:@"iPhone1,1"] ||
87                 [platform isEqualToString:@"iPhone1,2"]) return true;
88         return false;
89 }
90
91 - (void)viewWillAppear:(BOOL)animated {
92         [super viewWillAppear:animated];
93         NSLog(@"should load sound");
94         if ([self soundToPlay] != nil) {
95                 NSLog(@"will try to load sound");
96                 OSStatus error = AudioServicesCreateSystemSoundID((CFURLRef)[self soundToPlay], &beepSound);
97                 if (error != kAudioServicesNoError) {
98                         NSLog(@"Problem loading nearSound.caf");
99                 }
100         }
101 }
102
103 - (void)viewDidAppear:(BOOL)animated {
104     [super viewDidAppear:animated];
105         [overlayView setPoints:nil];
106         wasCancelled = false;
107         [NSTimer scheduledTimerWithTimeInterval: FIRST_TAKE_DELAY
108                                                                          target: self
109                                                                    selector: @selector(takePicture:)
110                                                                    userInfo: nil
111                                                                         repeats: NO];
112 }
113
114 - (void)takePicture:(NSTimer*)theTimer {
115         CGImageRef capture = UIGetScreenImage();
116         UIImage *scrn = [UIImage imageWithCGImage:CGImageCreateWithImageInRect(capture, [overlayView cropRect])];
117         Decoder *d = [[Decoder alloc] init];
118         d.delegate = self;
119         CGRect cropRect = overlayView.cropRect;
120         cropRect.origin.x = 0.0;
121         cropRect.origin.y = 0.0;
122         [d decodeImage:scrn cropRect:cropRect];
123 }
124
125 // DecoderDelegate methods
126
127 - (void)decoder:(Decoder *)decoder willDecodeImage:(UIImage *)image usingSubset:(UIImage *)subset{
128 #ifdef DEBUG
129         NSLog(@"DecoderViewController MessageWhileDecodingWithDimensions: Decoding image (%.0fx%.0f) ...", image.size.width, image.size.height);
130 #endif
131 }
132
133 - (void)decoder:(Decoder *)decoder
134   decodingImage:(UIImage *)image
135     usingSubset:(UIImage *)subset
136        progress:(NSString *)message {
137 }
138
139 - (void)presentResultForString:(NSString *)resultString {
140         self.result = [ResultParser parsedResultForString:resultString];
141         
142         if (beepSound != -1) {
143                 NSLog(@"about to play beep... trying...");
144                 AudioServicesPlaySystemSound(beepSound);
145         }
146 #ifdef DEBUG
147         NSLog(@"result string = %@", resultString);
148         NSLog(@"result has %d actions", actions ? 0 : actions.count);
149 #endif
150         //      [self updateToolbar];
151 }
152
153 - (void)presentResultPoints:(NSArray *)resultPoints
154                    forImage:(UIImage *)image
155                 usingSubset:(UIImage *)subset {
156         // simply add the points to the image view
157         [overlayView setPoints:resultPoints];
158 }
159
160 - (void)decoder:(Decoder *)decoder didDecodeImage:(UIImage *)image usingSubset:(UIImage *)subset withResult:(TwoDDecoderResult *)twoDResult {
161         [self presentResultForString:[twoDResult text]];
162         [self presentResultPoints:[twoDResult points] forImage:image usingSubset:subset];
163         // now, in a selector, call the delegate to give this overlay time to show the points
164         [self performSelector:@selector(alertDelegate:) withObject:[[twoDResult text] copy] afterDelay:1.0];
165         decoder.delegate = nil;
166         [decoder release];
167 }
168
169 - (void)alertDelegate:(id)text {        
170         if (delegate != nil) {
171                 [delegate scanResult:text];
172         }
173 }
174
175 - (void)decoder:(Decoder *)decoder failedToDecodeImage:(UIImage *)image usingSubset:(UIImage *)subset reason:(NSString *)reason {
176         decoder.delegate = nil;
177         [decoder release];
178         [overlayView setPoints:nil];
179         if (!wasCancelled) {
180                 [self takePicture:nil];
181         }
182         //[self updateToolbar];
183 }
184
185 @end