Tuesday, June 19, 2012

Using Google Maps with jQuery Mobile

I ran into some problems trying to use Google MapView with jQuery mobile in my PhoneGap app for Android. Basically the map view would load, displaying some of the map tiles, but it would show some grey tiles too. Scrolling or panning around the map would load new tiles but slightly off center, leaving some grey tiles showing.

The problem was that the map view was being initialized while it was on a hidden page--the div page that contained was the map was not being shown.

To solve the problem, instead of loading the map view in the $(document).ready() function I had to listen for the pageshow event and then initialize the map after the page had been loaded and the transition animations completed. Assuming you have something like:


<div data-role="page" id="map-page">
    <div data-role="content">
        <div id="map_canvas"></div>
    </div>
</div>


You can do:


$(document).ready(function() {
    $('#map-page').live('pageshow',mapPageChanged)    
});



var mapPageChanged = function(event) {
    console.log("Map page changed");
    $('#map_canvas').gmap(); // initialize Google map view with jQuery.ui.map plugin here
}


And your map view will stop acting confused.

Wednesday, December 7, 2011

Installing Ubuntu on your EeePC 1001PX

Installing another OS on your netbook for the first time can be frustrating. Here's one simplified guide.

These instructions install Ubuntu 10.10 on Asus EeePC 1001PX and may vary for other models.

What you'll need
* a 1GB+ USB thumb drive

1. Format your thumb drive to be FAT
* On Windows Vista, right click the drive and select format.
* Choose FAT (not FAT32) and format.

2. Download the latest BIOS update from Asus
* http://support.asus.com
* the latest version is the one labeled with the highest number, not sure why they leave old versions online
* rename the file to 1001PX.ROM and transfer to your thumb drive

3. Update your BIOS
* Shut down your netbook.
* Push the power button and hold Alt and press F2 repeatedly.
* The bios flash should find your usb and begin the flash.
* Verify by rebooting and pressing F2 during boot. Look under Main to verify your BIOS version matches the update you downloaded.

4. Download the latest version of Ubuntu (as of 11.04 the desktop and netbook versions of Ubuntu were merged)
* http://www.ubuntu.com/download/ubuntu/download
* Choose 32 bit

5. Make your USB bootable with Ubuntu ISO
* download UNetbootin app http://unetbootin.sourceforge.net/
* open the app, choose diskimage > ISO and select your downloaded ubuntu.iso
* verify your USB Drive is correct and click OK. Wait for it complete.

6. Change the boot order for your netbook
* During boot press F2
* Go to BOOT section and then the Boot Device Priority subsection
* Change REMOVABLE DEV. to be [1]
* Save Changes and Exit (F10)

7. Boot into Ubuntu Install
* During boot press TAB
* Select REMOVABLE DEV.
* You should be home free.. enjoy your new OS!

Tuesday, September 13, 2011

How to import CameraPreview from Android ApiDemos

Let's say you want to tinker with the CameraPreview class from the Android ApiDemos that you downloaded from the ADT Eclipse plugin, but you don't want to mess up that nice shiny ApiDemos package.

You'll probably want to start a new Android project and then import the CameraPreview.java file into your package namespace under your project's src folder.

Once you do that you'll see you have some errors, so let's clean those up.

Let's start by first retrieving the camera_menu.xml file from the ApiDemos project res/menu folder and importing that into our res/layout folder. This is the menu that will display when you hit the menu key.

We're still missing some strings, so let's add the missing strings from res/values/strings.xml to our res/values/strings.xml file.
 <string name="density_title">Density: Unknown Screen</string>  
 <string name="camera_alert">Device has only one camera!</string>  
 <string name="switch_cam">Switch Camera</string>  

Finally we'll change the location for our camera_menu to it's new location. Change line 109 to
 inflator.inflate(R.layout.camera_menu, menu);  
We've now cleaned up all the errors (hopefully)! But if you launch your new project you'll notice nothing special happens. That's because we haven't called our new CameraPreview activity that we were so careful to import.

Let's add a call in the onCreate() method of our main activity
 startActivity(new Intent(this, CameraPreview.class));  
and then add this activity to our AndroidManifest.xml
 <activity android:name=".CameraPreview"></activity>  
If we launched out activity now, we'd still be jumping the gun and would get a force close. The last thing we should (which probably should have been first!) is to add permission to use the camera by adding this line to our AndroidManifest.xml
 <uses-permission android:name="android.permission.CAMERA" />  
Now if you launch your new sample app you should see the camera preview. Now you're free to tinker as you'd like without disturbing your original copy of the ApiDemos code.

Friday, April 29, 2011

Inspiring the generation of tomorrow

Had a truly amazing opportunity yesterday to setup a workshop for Take Your Child to Work Day at my company.

With inspiration from Daniel Suarez's popular tech-heavy visionary book Daemon, the storyline we came up with set the stage for Cyber Security Investigators. We invited the children to enter a world where a prototype A.I. system had been built into a building. What's A.I.? "Artificial Intelligence--it's a computer system that appears to make rational decisions" and that came from a 12 year old! After asking how the building could "understand" what was going on within itself, the children's imagination would surprise you. Security cameras, audio sensors, motion detectors, badging systems, and signal receivers were all listed as the eyes and ears of the building.

After describing the A.I. system, we explained the building would attempt to detect suspicious activity and report this activity on a secret AR layer. The activity would be logged through tweets and visualized through an Augmented Reality app Layar for the iPhone. Each piece of suspicious activity was accompanied by an encrypted tweet that contained more information.

The children were then told the building had a security breach and some information was stolen--they were the investigators trying to uncover who stole the information and where they went. Sorting through the tweets, they identified the ones that seemed most suspicious and then attempted to use a decryption app Strambler to decrypt the message.

It was soon discovered that they needed the key phrase used to originally encrypt the message. After requesting the security imagery for that room, they were provided with a QR code. Scanning the QR code with the iPhone app ScanLife showed them the picture of an easily recognizable object. Many immediately said "Could this be the passcode?" After entering the words like "bear", "rose", and "yoshi" they were delighted to uncover the hidden message.

Based on these secret messages, they had to determine whether the reported action was legitimately suspicious and isolate any clues. A pair of decimal numbers in one message about "Exchanging downloaded files" prompted further questions: Was it a time? An exchange rate? "They're GPS coordinates!" exclaimed one of their older team members. "We need a map app" and it wasn't much longer before they were able to deduce that the thief must be traveling to the National Aquarium in Baltimore. Why? Because "They could be tracked if they sent the files over the internet"

It was truly amazing to watch the children learn to use the iPad and iPhone apps to do true detective like work. My assumption that 10 and 12 year olds were already familiar with iPads was not exactly accurate. One team who couldn't even figure out how to open an app at the beginning, quickly learned how to copy & paste text all using a series of touch gestures, navigating between apps and deducing their functionality without anything more than a hint here and there from us as facilitators. Would you believe they actually caught up to the other groups and actually won the race to discover the thief's exchange point?

One can not cease to be amazed in the ability of young children to grasp so quickly how to navigate this rather complicated process. And not just for the sake of repeating a learned task, but also in analyzing the data outcomes of a task and combining them to make the right decisions and arrive at a correct conclusion. The future will certainly be an exciting time as these young ones, not more than 15 years behind myself in age, will soon be joining the engineering workforce innovating and creating the technological world of tomorrow!

Wednesday, November 17, 2010

Investigating initialization errors

I spent some time this evening investigating two errors thrown by XCode that baffled me for a bit today.

I wrote some methods like this:

#import "MyClass.h"

@implementation MyClass

- (void)refreshImageView:(UIImageView *)imageView {
   
    CGFloat newHeight = [self modifyHeightFromFrame:imageView.frame];
   
    // ...
}

- (CGFloat)modifyHeightFromFrame:(CGRect)frame {
    float modifier = .10;
    return frame.size.height * modifier;
}

@end

My build failed with the following error: "Incompatible types in initialization" appearing at the line in which I was calling the method. Obviously when assigning a CGFloat to a CGFloat everything looks OK, so why the error?

The problem was I had not yet put the method signature into the header file. I found that because the method returning the CGFloat value was located below the method call, the compiler didn't know about the method or what its return type was. Including a method signature like the one below solved the problem.

/* MyClass.h */

@interface MyClass : NSObject {
    // ...
}

// Method signatures
- (CGFloat)modifyHeightFromFrame:(CGRect)frame;

@end

I wanted to further investigate the reason why you receive this error instead of a nice warning message, because typically in cases like this you will receive a warning like this one

'Class' may not respond to '-method'Name'

However, this case is slightly different (I'll explain why shortly) because the error thrown trumps any warnings and we therefore do not receive that helpful warning. The warning is helpful in two ways: 1) it clues me in to the fact that I have forgotten to add my method signature to the class header file or have forgotten to include the header file altogether and 2) the warning is typically accompanied by a helpful explanation. When viewing the Build Results a little note appears below the warning. If you click 'more' you could see the message explains

Messages without a matching method signature will be assumed to return 'id' and accept '...' as arguments.

What this tells us is that because XCode doesn't recognize the method (due to the missing signature/method declaration), it will assume the return type of the method to be an id (the value of which is a memory address pointing to an object of type void*).

OK fine, so why all the fuss? Well if we take a deeper look into CGFloat we discover that it is really just a typedef for float or double depending on your architecture. And then we find that float/double values (non-integer, primitive data types) can not receive a cast of a pointer value (memory address). Here lies the explanation behind the previously mysterious error. The compiler was trying to initialize a float value with a memory address, and complained with an initially ambiguous error.

Now, however, we are more informed what this error message could mean in the future and will know possibly where to look when we don't receive our nice little warning message.

I might also note that when trying to initialize a structure such as CGRect or CGSize with an undeclared method, you will receive an equivalent error message:

Invalid initializer

Which essentially means "Hey! I can't initialize a structure with only a memory address." And if you try to cast the result instead, you'll receive an error message:

Conversion to non-scalar type requested

All that being said, it all boils down to this: Don't forget to declare your method signatures and include your header files!

Friday, October 29, 2010

Discovering online developer resources

One reason for which I had the desire to start a blog was to create a storage point for all the useful information that I encounter on a day-to-day basis as a software developer. Many times I'll spend an hour researching a problem or a topic and thought it would be great to store my list of aggregated sources and findings in a spot publicly accessible by others.

So today I'll share two quick links I found just a minute ago:
  • Dr Dobbs - Online software journal articles and blogs. A resource I am hoping will help shed light on the latest encouraged practices within the sphere of development.
  • FreeTechBooks - Probably quite the opposite of staying current, but free access to hundreds of tech books (most of which at initial perusal seem a bit dated).