Wednesday, July 7, 2010
Friday, June 25, 2010
Canadian iPad Data Plans Compared
I was curious about how the iPad plans that were announced by Bell, Rogers and Telus compared, where the break points were, and so forth. So I threw together a Google Spreadsheet to do some quick math on the plans. Assuming I read the plan rules correctly, I think the lessons are as follows:
- Bell and Rogers have eerily similar plans, like one copied the other, or both took a suggestion from Apple.
- The $15 plan offered by Bell and Rogers saves $5 over the $20 plan from Telus until you use more than 250MB.
- Telus' one-price plus overage model is cheaper than Bell and Rogers' $35 plan from 250MB-800MB.
- From 800MB to 5GB, Bell and Rogers $35 plan seems to be the way to go, because you'll be paying more than $35 by the time you pay Telus for your overage.
- After 5GB, it seems like Telus' plan, which maxes out at $50, would be cheaper than paying Rogers or Bell for another $35/5GB, assuming Telus doesn't cut you off.
- Telus does have fine print saying "Subject to a monthly data limit of 5GB", but they're not very clear what happens if you hit that limit.
- Neither Rogers nor Bell explains what happens when you reach your cutoff. If you run out of data on the $15 plan, can you upgrade to the $35 plan for $20, keeping the original timeframe? Can you buy a new 30-day window of $15?
Wednesday, June 16, 2010
The Future of iPhone Multi-Tasking
Marco Arment on iPhone Multitasking:
One of my most common feature requests is for Instapaper to periodically download articles in the background. A lot of people forget to launch the app to let it download content before going underground or boarding a plane.
I’ve already received multiple emails from people who are excited for iOS 4’s multitasking because they can’t wait for this to finally stop being an issue, because they think Instapaper will be able to download articles periodically in the background.
It’s painful to respond, crushing their hopes, to tell them that the iOS multitasking system doesn’t allow me to do that.
The solution he proposes:
- The application gives the system an NSURLRequest and an ideal refresh interval, such as every 30 minutes, every few hours, or every day.
- iOS executes that request, whenever it deems that it should, and saves the response to a local file.
- Next time the application launches, iOS hands it an NSData of the most recent response.
Idle Processing
posted at 8:59 AM Labels: ios, ipad, iphone, multitasking
Monday, April 19, 2010
Telus iPhone Visual Voicemail
I was pleased to see that Telus announced and rolled out Visual Voicemail, as was implied in the Carrier Update file I received and analyzed.
posted at 2:39 PM Labels: carrier update, iphone, telus, visual voicemail
Friday, April 2, 2010
OS X 10.6.3 and GWT 1.x
Safari 4.0.4, when it came out, had an issue with respect to GWT development, causing the GWT hosted mode browser to crash on load. As a result, I didn't take the Safari 4.0.4 update. When Safari 4.0.5 came out, reports indicated that it wasn't any better, despite the fact that some of the interim builds of WebKit had been used successfully, so I didn't take that update either.
posted at 1:08 PM Labels: development, google web toolkit, gwt, mac os x, os x, safari, software
Wednesday, March 17, 2010
Telus iPhone Carrier Update
This morning, iTunes warned me that there was a carrier update available for my iPhone. The 'more info' button opened a link that explained the process, but didn't offer any details about what the update contained, other than updates with regard to my settings for my carrier, Telus.
$ mkdir ~/telus
$ cp ~/Library/iTunes/iPhone\ Carrier\ Support/Telus_ca.ipcc ~/telus/telus.zip$ cd ~/telus$ unzip telus.zip
Archive: telus.zip
creating: Payload/
creating: Payload/Telus_ca.bundle/
inflating: Payload/Telus_ca.bundle/carrier.plist
inflating: Payload/Telus_ca.bundle/Default_CARRIER_TELUS.png
inflating: Payload/Telus_ca.bundle/FSO_CARRIER_TELUS.png
inflating: Payload/Telus_ca.bundle/Info.plist
inflating: Payload/Telus_ca.bundle/version.plist
$ plutil -convert xml1 *.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BookmarkURLs</key>
<array>
<dict>
<key>BookmarkName</key>
<string>TELUS Web</string>
<key>BookmarkURL</key>
<string>http://m.telusmobility.com/homepage</string>
</dict>
</array>
<key>CarrierBookmarks</key>
<array>
<dict>
<key>Title</key>
<string>Web TELUS</string>
<key>URL</key>
<string>http://m.telusmobility.com/homepage</string>
</dict>
</array>
<key>CarrierName</key>
<string>TELUS</string>
<key>IntlDataRoamingSwitch</key>
<true/>
<key>MMS</key>
<dict>
<key>GroupModeEnabled</key>
<false/>
<key>MMSC</key>
<string>http://aliasredirect.net/proxy/mmsc</string>
<key>MaxRecipients</key>
<integer>20</integer>
<key>Proxy</key>
<string>74.49.0.18:80</string>
</dict>
<key>MaxBluetoothModemConnections</key>
<integer>1</integer>
<key>MyAccountURL</key>
<string>http://m.telusmobility.com/homepage</string>
<key>MyAccountURLTitle</key>
<string>TELUS Web</string>
<key>Services</key>
<array>
<dict>
<key>ServiceCode</key>
<string>#411</string>
<key>ServiceName</key>
<string>Directory Assistance</string>
</dict>
<dict>
<key>ServiceCode</key>
<string>#411</string>
<key>ServiceName</key>
<string>Assistance-annuaire</string>
</dict>
<dict>
<key>ServiceCode</key>
<string>#8294</string>
<key>ServiceName</key>
<string>TAXI</string>
</dict>
<dict>
<key>ServiceCode</key>
<string>#2886</string>
<key>ServiceName</key>
<string>Roadside Assistance</string>
</dict>
<dict>
<key>ServiceCode</key>
<string>#2886</string>
<key>ServiceName</key>
<string>Assistance Routière</string>
</dict>
</array>
<key>ShowCallForwarded</key>
<false/>
<key>ShowCallForwarding</key>
<false/>
<key>ShowDialAssist</key>
<false/>
<key>ShowTTY</key>
<false/>
<key>StatusBarImages</key>
<array>
<dict>
<key>AllowPrefixMatching</key>
<false/>
<key>CarrierName</key>
<string>TELUS</string>
<key>DefaultImage</key>
<string>Default_CARRIER_TELUS.png</string>
<key>FullScreenOpaqueImage</key>
<string>FSO_CARRIER_TELUS.png</string>
</dict>
<dict>
<key>AllowPrefixMatching</key>
<false/>
<key>CarrierName</key>
<string>TELUS UMTS</string>
<key>DefaultImage</key>
<string>Default_CARRIER_TELUS.png</string>
<key>FullScreenOpaqueImage</key>
<string>FSO_CARRIER_TELUS.png</string>
</dict>
</array>
<key>StockSymboli</key>
<array>
<dict>
<key>symbol</key>
<string>T.TO</string>
</dict>
<dict>
<key>symbol</key>
<string>TU</string>
</dict>
</array>
<key>SupportedSIMs</key>
<array>
<string>302220</string>
</array>
<key>SupportsNITZ</key>
<true/>
<key>SupportsUserBusyCauseCode</key>
<true/>
<key>VVMIgnoresIntlDataRoaming</key>
<false/>
<key>VisualVoicemailServiceName</key>
<string>IMAP</string>
<key>apns</key>
<array>
<dict>
<key>apn</key>
<string>sp.telus.com</string>
<key>password</key>
<string></string>
<key>signature</key>
<data>
...
</data>
<key>type-mask</key>
<integer>7</integer>
<key>username</key>
<string></string>
</dict>
<dict>
<key>apn</key>
<string>isp.telus.com</string>
<key>password</key>
<string></string>
<key>signature</key>
<data>
...
</data>
<key>type-mask</key>
<integer>48</integer>
<key>username</key>
<string></string>
</dict>
<dict>
<key>apn</key>
<string>sp.telus.com</string>
<key>password</key>
<string></string>
<key>signature</key>
<data>
...
</data>
<key>type-mask</key>
<integer>6</integer>
<key>username</key>
<string></string>
</dict>
</array>
<key>com.apple.voicemail.imap</key>
<dict>
<key>BeaconAddress</key>
<string>474663</string>
<key>ClientManagesTrash</key>
<false/>
<key>GreetingNotification</key>
<true/>
<key>MaxGreetingDuration</key>
<integer>60</integer>
<key>MaxPINLength</key>
<integer>10</integer>
<key>MinPINLength</key>
<integer>4</integer>
<key>UsesMWI</key>
<true/>
<key>UsesSSL</key>
<false/>
</dict>
<key>voicemail_context</key>
<integer>0</integer>
</dict>
</plist>
posted at 9:02 AM Labels: carrier update, investigation, iphone, telus
Monday, January 25, 2010
Composite Event Handler Registrations in GWT
In my previous entry, I wrote up a class for displaying Input Prompts in GWT. As I started to fold that code into my project, I realized that I didn't expose the handler registrations, which would make it impossible to remove the event handlers if and when the text fields for which input prompts were displayed were created and removed during the lifecycle of the application.
Because the Input Prompt registers handlers for both Blur and Focus, there are two registrations. It's not easy to return two values from a single method, and frankly, I don't think a class using InputPrompt should have to know or care what events it's employing in great detail. As a result, I've created a composite event handler registration to return:
package com.codiform.gwt.event;
import java.util.ArrayList;
import java.util.List;
import com.google.gwt.event.shared.HandlerRegistration;
public class CompositeHandlerRegistration implements HandlerRegistration {
private Listregistrations;
public CompositeHandlerRegistration() {
registrations = new ArrayList();
}
void add( HandlerRegistration registration ) {
if( registration instanceof CompositeHandlerRegistration ) {
CompositeHandlerRegistration composite = (CompositeHandlerRegistration) registration;
registrations.addAll( composite.getRegistrations() );
composite.clear();
} else {
registrations.add( registration );
}
}
private ListgetRegistrations() {
return registrations;
}
public void removeHandler() {
if ( registrations.size() > 0 ) {
for ( HandlerRegistration item : registrations ) {
item.removeHandler();
}
clear();
} else {
throw new IllegalStateException( "Composite handler registration is currently empty, and cannot remove handlers." );
}
}
private void clear() {
registrations.clear();
}
}
If a composite handler registration is passed to another composite handler registration, I flatten them; this might be unnecessary. In the spirit of YAGNI, I won't be at all unhappy if you decide you don't need that capability. I also decided I preferred to clear my local references to any inner handler registrations as soon as they've been removed, rather than hanging on to them indefinitely.
All in all, this is pretty simple GWT code, but seemed worth following up on the previous entry to talk about the need for handler registrations.
Friday, January 22, 2010
Input Prompt Pattern in GWT
For a GWT project I'm working on, I've reached a point where I wanted to apply input prompts to a text box; this doesn't seem to be something that's built in to the basic GWT framework, or an easily-located extension. For that matter, I couldn't find anyone who'd done it and blogged about it, although it might be that they've used different terminology.
I thought it was worth a quick experiment to see how easy they would be to apply, and this is what I came up with:
package com.codiform.gwt.widget;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
public class InputPrompt implements BlurHandler, FocusHandler {
private String promptText;
public InputPrompt( String text, TextBox... inputs ) {
this.promptText = text;
for( TextBox item : inputs ) {
apply( item );
}
}
public void apply( TextBox input ) {
input.addBlurHandler( this );
input.addFocusHandler( this );
applyPrompt( input );
}
public void onBlur( BlurEvent event ) {
TextBox blurred = (TextBox) event.getSource();
applyPrompt( blurred );
}
private void applyPrompt( TextBox input ) {
if( input.getText().isEmpty() ) {
input.setText( promptText );
input.addStyleName( "inputPrompt" );
}
}
public void onFocus( FocusEvent event ) {
TextBox focused = (TextBox) event.getSource();
if( promptText.equals( focused.getText() ) ) {
focused.setText( "" );
focused.removeStyleName( "inputPrompt" );
}
}
}
The final version has some project-specific tweaks (interface for the textbox to make this code testable with mocks, a style name in the project namespace), but for the most part the above code seems to do the trick well and I'll be applying it shortly.