Saturday, January 31, 2009

iPhone Becomes a Noise Meter

iPhone is a device with practically unlimited possibilities and potential. Well, the hardware of iPhone is fantastic, however, what makes it a real wonder device is the abundance of applications and software that have been pouring in for the past several months.

A new cool application called Noise Meter transforms your iPhone into a portable noise meter. The application is marginally simple. You start it and then tap the big round button and voila.

What I liked about this application is that it gives you human understandable information. If you are a pro, you know what a dB means but what about mere mortars? So, the application simply gives you the level of noise in plain English. Namely, noise levels are grouped as follows:

0-20: Quiet, suitable for living and sleeping
20-40: Comfortable, suitable for office
40-60: Busy, suitable for business
60-80: Bustling, suitable for traffic
80-100: Noisily, suitable for factory
>100: Terrible, don't stay for health

As soon as I downloaded the application, I started testing different places. Believe me, this application is very useful and exciting and best of all, it's absolutely free.

The download link is: http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=303084018&mt=8

Thursday, January 29, 2009

Longer Spinning & Blurring

I can't tell you how many times I've been asked lately how to do the "UrbanSpoon Effect".

Note: There is a newer version of this code available here.


Now, I have no idea exactly how the folks at UrbanSpoon did their application, but they did it well. I don't have time for a full tutorial right now, or to do a full implementation of the effect, but in the process of helping somebody in a forum, I did write a little sample application that shows the basic theory of how to make your UIPickerView go round and round for longer.

As I said, this project nowhere near as polished as what UrbanSpoon does - I cheated on the blurring because I hit some bugs while porting my NSImage convolution kernel code to work with UIImage and I don't have the time to debug something that gnarly right now. My "blur" is just a double resize - down then back up. It's really just interpolation, but it sorta makes it blurry. I probably wouldn't use that method of blurring in a real application but, then again, I'd be getting paid for a real application.



This application does support using the accelerometer to start the spin. In order to make the picker view spin longer, I subclassed UIPickerView. My subclass had exactly one method. This is an undocumented method that returns the duration of the spin, so you just return the number of seconds you want your spin to go for:

#import "JLPickerView.h"

@implementation JLPickerView
- (double)scrollAnimationDuration
{
return 5.0;
}
@end


The other key thing to note in this application is that my UIPickerViewDataSource lies about how many rows each component has. I have a constant called kRowMultiplier. I take the count of the array that corresponds to a particular component, and I multiply it by kRowMultiplier. This value is currently set to 100, so if the array that feeds a component has ten items, my datasource lies and says there are a thousand, and then it just keeps feeding the same ten items over and over in the same order by calculating the actual row in the array to use:

int actualRow = row%[[self arrayForComponent:component] count];

This creates a component with the same values repeated over and over.

When the view first appears, I load arrays with views containing both the blurred and unblurred data. You don't want to be programmatically blurring the values over and over when the spin happens, so we do it once and store the values in arrays. I then set the component's row to a value in the middle. This means that the user will never see the blank rows above and below the real values, which helps create the illusion of endless spinning.
[picker selectRow: [component1Data count] * (kRowMultiplier / 2) inComponent:0 animated:NO];

Now, when a value is selected in the picker, I do a bait-and-switch back to the middle. I move the component to the same value they're currently on, but back in the middle of the wheel. This way, no matter what happens, they'll never see the blank rows at the top or bottom. Since I'm moving them to the same value and the surrounding values are the same, and I tell it not to animate the change, the user has no idea it has happened.
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
NSArray *componentArray = [self arrayForComponent:component];
int actualRow = row%[componentArray count];

int newRow = ([componentArray count] * (kRowMultiplier / 2)) + actualRow;
[picker selectRow:newRow inComponent:component animated:NO];

}

Finally, when the spin button is pressed, or the user shakes the phone, I calculate a random number for each component. This number is a value between 0 and the size of the array minus 1. This tells me what the new, randomly selected value will be. Then I move the components (again, without animating) to the corresponding row near the top or bottom of the dial, and then animate to the selected value at the other end of the wheel.
- (IBAction)spin
{
if (! isSpinning)
{
// Calculate a random index in the array
spin1 = arc4random()%[component1Data count];
spin2 = arc4random()%[component1Data count];
spin3 = arc4random()%[component1Data count];

// Put first and third component near top, second near bottom
[picker selectRow:([picker selectedRowInComponent:0]%[component1Data count]) + [component1Data count] inComponent:0 animated:NO];
[picker selectRow:(kRowMultiplier - 2) * [component2Data count] + spin2 inComponent:1 animated:NO];
[picker selectRow:([picker selectedRowInComponent:2]%[component3Data count]) + [component3Data count] inComponent:2 animated:NO];

// Spin to the selected value
[picker selectRow:(kRowMultiplier - 2) * [component1Data count] + spin1 inComponent:0 animated:YES];
[picker selectRow:spin2 + [component2Data count] inComponent:1 animated:YES];
[picker selectRow:(kRowMultiplier - 2) * [component3Data count] + spin3 inComponent:2 animated:YES];

isSpinning = YES;

// Need to have it stop blurring a fraction of a second before it stops spinning so that the final appearance is not blurred.
[self performSelector:@selector(stopBlurring) withObject:nil afterDelay:4.7];
}
}


I set a variable called isSpinning so that I know whether to provide blurred or unblurred data to the spinner. I have the spin set for 5 seconds, so 4.7 seconds in the future, I set the value back to NO. This cause it to stop blurring a moment before the spinning stops. This is done so that the final words displayed will not be blurred.

You can download the sample project here.

One note, though: I have used a couple of undocumented, private methods in this project. I ordinarily shy away from doing that, but in the sake of getting this code out the door quickly, I did. I use one undocumented method for resizing the UIImage in order to create the fake blur effect, and another one to keep the picker from making sounds when I initially set the values because I don't want the user to realize I'm moving the picker - that would shatter the illusion. These are pretty subtle uses of undocumented methods so I doubt they'd get your application rejected, but they could. They're also not methods that are likely to change. But, again, they could - that's always a risk with undocumented methods, so caveat emptor - use at your own risk. If you want to play it safe, to a real motion blur and take out the calls to UIPickerView's setSoundsEnabled: method.

Wednesday, January 28, 2009

Another SQLite Library

I just learned of another library for using SQLite 3 from the iPhone called iPhoneLite3. It's still a pretty young project (classified as "alpha"), and takes a different approach than I did in sqlitepersistentobjects, but looks to be a project worth keeping an eye on.

Beginner Tip #2 - How to Arrange iPhone Icons

Unlike other mobile devices, arranging icons on the iPhone is extremely easy. However, it is not very easy to guess how to do this. Well, as a matter of fact, I've come to this feature purely accidentally when I first got the device. So, here's how you do it:

1. Tap and hold your finger on any of the icons until they start shaking. Don't panic, there's nothing wrong with your phone (well, I was really scared when the icons started shaking as I had no idea what was going on with them, really funny).

2. Now you can simply drag the icons and place them anywhere you want them. You have complete freedom in re-arranging them.

3. When you are happy with the organization of your icons, press the iPhone Home button to save your changes.

That's it.

If you liked this tip, you may like to check out a post listing all of my beginner tips.

Tuesday, January 27, 2009

Firetask - Action Management at its Best

Effective and efficient time management is important not only for professional managers, but for everyone appreciating time. While there "are" some folks with "abundance" of time (take our AJ for example and her two-hour showers), for us, mere mortars, time is extremely scarce. In traditional time management priorities play a central role. However, a time management method invented by David Allen, called Getting Things Done (GTD for short) places more emphasis on control and perspective.

Computers and especially smart phones are very good aids for managing your time. It shall not be a surprise that numerous applications exist for task management for any platform. However, most of the applications that I've seen so far (not only for iPhone but for Symbian and Windows Mobile) are too simplistic and they follow the traditional time management methodology. A new iPhone application called Firetask is extremely useful for managing your time and literally getting things done. Firetask has just been released by Gerald Mesaric Task 1 Consulting.

What I liked about Firetask is that it combines both the traditional and the above mentioned GTD approaches.

The application features a nice and intuitive interface and sleek design. The "Today" screen is the central part of the application. It shows only the tasks due today and in the following days together with the first open task per project. Thus, you are not overloaded with irrelevant tasks. Another very interesting feature is the "Waiting for" list. Its main purpose is to keep track of delegated tasks. The Inbox is used for quickly gathering thoughts and ideas.

Firetask 1.0 is now available through Apple's iTunes App Store for $4.99 (USD) for iPhone
and iPod touch. The application supports English and German user interface.

You can learn more about Firetask at http://www.firetask.com. I also recommend that you check out David Allen Company web site at http://www.davidco.com.

Finally, I would like to thank Gerald Mesaric Task 1 Consulting for providing me with this nice and useful application.

Twittering iPhone Developer List

Tim Haines, the developer of the excellent BurnBall game, has started a list of iPhone developers who use Twitter. The last time I checked, there were over 100 iPhone devs on the list. If you have a Twitter account, go add yourself to the list. There is no minimum requirement and no test will be administered, it's just an informal list of people interested in iPhone development who also use Twitter.

D'oh, it helps if I include the link, doesn't it?

Sunday, January 25, 2009

The Latest 3G iPhone Unlocking Software Released

A new 3G iPhone Unlock software is launched by UK entrepreneur Mark Scott and his team of software developers. It gives iPhone customers the chance to use their handsets with any network provider worldwide and also enabling the use of third party applications.

The main reason of development of this software comes after complaints from prospective customers regarding the handset being exclusively available on the o2 and AT&T networks, depending on the country of origin, and disappointment came over finding that the phone lacked standard features such as MMS, video recording and instant messaging amongst others.

According to the PRWEB, the contemporary 3G iPhone unlocking software also enables all of these features and comes with full 24 hour customer support via Email, Live Chat and by Phone.

"The Apple iPhone is a fantastic piece of technology, but that doesn't mean it's perfect." Mark Scott, Company Director of iPhone unlocking Ltd. "Using our 2G and 3G iPhone unlock software, the iPhone becomes compatible with all GSM network providers worldwide and enables the use of thousands of great 3rd party applications, therefore making the iPhone arguably the best mobile handset available on the market today."

Originally posted on Blogvasion.com

Beginner Tip #1 - How to Rename Your iPhone

Sometimes simple and obvious things are difficult to accomplish. Even such a simple action as renaming your iPhone may not be clear immediately. At least, I have seen a number of people asking this on different forums. Generally, Apple software is one of the best in terms of usability. Most of the aspects are well thought out and designed. Unfortunately, renaming iPhone is an exception.

It turns out that renaming your iPhone is very easy but this functionality is not apparent and visible immediately. Simply, start iTunes and double-click your phone in the DEVICES area. Most people right click the phone and then expect to see the rename command in the shortcut menu. It is a bit disappointing that we don't see a command to rename the phone in the short-cut menu. But again, double clicking does the job.

If you liked this tip, you may like to check out a post listing all of my beginner tips.

iPhone Beginner Tips

Recently, I've been getting numerous e-mails from our readers to post beginner tips for iPhone users. So, here we go. Beginning from this week, I will be regularly posting beginner iPhone tips and links to interesting resources featuring beginner tips and how-to articles. You may wish to bookmark this post, since I will be adding links to each tip here. At the same time, you can always see all tips by navigating to them from the labels menu.

Tip #1 - How to Rename Your iPhone

Tip #2 - How to Arrange iPhone Icons

Tip #3 - How to Make Screenshots on iPhone

Tip #4 - How to Bring Your Voicemail Button to Life

Tip #5 - How to Add an Extension to a Contact’s Phone Number

Tip #6 - How to set up parental control on iPod and iPhone touch

Tip #7 - Iphone voice commands

Tip #8 - How to make your iPhone battery last long?

Tip #9 - Some Secret Tips!

Tip #10 - Hard and Soft Reset on iPhone 4

Tip #11 - Improve iPhone 4 Battery Life

Tip #12 - Tips for Great iPhone Photos

Tip #13 - How To Turn Battery Percentage Meter On

Tip #14 - Siri Tips for Your iPhone 4S

Tip #15 - How To Teach Siri to Tweet

Tip #16 - 4 Quick Tips For iPhone4S

Tip #17 - 10 secrets about SIRI

Friday, January 23, 2009

A Better Generic Date Picker

I've tweaked my generic date picker class so it matches, pixel-for-pixel, the date picker used by Apple's built-in apps like the Address Book (Contacts.app), and also fixed some bugs in the previous version.



Here is the code that implements it. Use is exactly the same as with the previous version.

Note: if you copied this before about 5:30pm EST, Friday January 23, 2009, you might want to re-copy it. There was a memory leak thanks to me forgetting to release the the date formatter instance.

DateViewController.h
/*
DateViewController.h
*/


#import <UIKit/UIKit.h>

@protocol DateViewDelegate <NSObject>
@required
- (void)takeNewDate:(NSDate *)newDate;
- (UINavigationController *)navController; // Return the navigation controller
@end


@interface DateViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
{
UIDatePicker *datePicker;
UITableView *dateTableView;
NSDate *date;

id <DateViewDelegate> delegate; // weak ref
}
@property (nonatomic, retain) UIDatePicker *datePicker;
@property (nonatomic, retain) UITableView *dateTableView;
@property (nonatomic, retain) NSDate *date;
@property (nonatomic, assign) id <DateViewDelegate> delegate;
-(IBAction)dateChanged;
@end


DateViewController.m
/*
DateViewController.m
*/

#import "DateViewController.h"

@implementation DateViewController
@synthesize datePicker;
@synthesize dateTableView;
@synthesize date;
@synthesize delegate;

-(IBAction)dateChanged
{
self.date = [datePicker date];
[dateTableView reloadData];
}
-(IBAction)cancel
{
[[self.delegate navController] popViewControllerAnimated:YES];
}
-(IBAction)save
{
[self.delegate takeNewDate:date];
[[self.delegate navController] popViewControllerAnimated:YES];
}
- (void)loadView
{
UIView *theView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.view = theView;
[theView release];

UITableView *theTableView = [[UITableView alloc] initWithFrame:CGRectMake(0.0, 67.0, 320.0, 480.0) style:UITableViewStyleGrouped];
theTableView.delegate = self;
theTableView.dataSource = self;
[self.view addSubview:theTableView];
self.dateTableView = theTableView;
[theTableView release];

UIDatePicker *theDatePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0.0, 200.0, 320.0, 216.0)];
theDatePicker.datePickerMode = UIDatePickerModeDate;
self.datePicker = theDatePicker;
[theDatePicker release];
[datePicker addTarget:self action:@selector(dateChanged) forControlEvents:UIControlEventValueChanged];
[self.view addSubview:datePicker];




UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc]
initWithTitle:NSLocalizedString(@"Cancel", @"Cancel - for button to cancel changes")
style:UIBarButtonItemStylePlain
target:self
action:@selector(cancel)]
;
self.navigationItem.leftBarButtonItem = cancelButton;
[cancelButton release];
UIBarButtonItem *saveButton = [[UIBarButtonItem alloc]
initWithTitle:NSLocalizedString(@"Save", @"Save - for button to save changes")
style:UIBarButtonItemStylePlain
target:self
action:@selector(save)]
;
self.navigationItem.rightBarButtonItem = saveButton;
[saveButton release];

self.view.backgroundColor = [UIColor groupTableViewBackgroundColor];

}

- (void)viewWillAppear:(BOOL)animated
{
if (self.date != nil)
[self.datePicker setDate:date animated:YES];
else
[self.datePicker setDate:[NSDate date] animated:YES];

[super viewWillAppear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

- (void)dealloc
{
[datePicker release];
[dateTableView release];
[date release];
[super dealloc];
}
#pragma mark -
#pragma mark Table View Methods
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

static NSString *DateCellIdentifier = @"DateCellIdentifier";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:DateCellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:DateCellIdentifier] autorelease];
cell.font = [UIFont systemFontOfSize:17.0];
cell.textColor = [UIColor colorWithRed:0.243 green:0.306 blue:0.435 alpha:1.0];
}

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"MMMM dd, yyyy"];
cell.text = [formatter stringFromDate:date];
[formatter release];


return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
@end