config.xml changes for iOS and Android

Ever since PhoneGap 2.0, we have been trying to migrate to the W3C Widget Specification so that Apache Cordova’s configuration would be more in line with the configuration found in PhoneGap Build, just to provide one example. The new format that we will be migrating to for PhoneGap 3.0 may be a surprise, but it’s relatively easy to migrate to the new format.

widget vs cordova:

Since we are adopting the widget specification, the document must be a widget document, as specified as this header:

<widget xmlns = "http://www.w3.org/ns/widgets"
id = "io.cordova.helloCordova"
version = "2.0.0">

There are other tags such as description, and author that are mostly ignored by the current Android implementation. The first relevant tag is the access tags for whitelisting:

Whitelisting:

Currently, we only whitelist http and https sites, and we do not support specifying a port in the whitelist. The whitelist looks like this:

<access origin="cordova.apache.org"/>

or

<access origin="*.apache.org"/>

or

<access origin="apache.org" subdomains="true">

Content:

The start page is specified in this document, Cordova Android and iOS supports both local and remote documents:

<content src="index.html" />

or:
<content src="http://mysite.com/index.html" />

Preferences:

The preferences may or may not be platform-specific, and consist of name/value pairs. More information can be found in our Cordova Documentation:

<preference name="loglevel" value="DEBUG" />

Features:

Instead of specifying a plugin, we now specify features and the platforms that they are associated with, for example:

<feature name="Echo">
<param name="android-package" value="org.apache.cordova.Echo"/>
<param name="ios-package" value="CDVEcho"/>
</feature>

In the above example, we are migrating the Echo plugin over to Android and iOS. The feature is called Echo across all platforms, so this is the feature name. If you have a plugin that has a different name across platforms, each of them will need their own feature tags. The following child tags indicate where each type of package could be found. On Android, Cordova Plugins are Java classes, so the full class name, including the namespace belongs in the value. On iOS, Cordova Plugins are Objective-C classes, so you would only use the class name as the value.

There are additional features in the config.xml, but this should cover the basic ones that you will need when migrating from the old format. More information can be found in our documentation.

What else is new in Cordova Android 2.4.0

Normally, Simon Macdonald, who also works on Apache Cordova, writes a blog post listing the new features that landed. However, there’s a feature that should be added to that post that I’ll explain below.

Additional Preferences in config.xml:

Certain features, such as the splashscreen, the error URL and timeouts in the past were undocumented, and would have to be added to the activity at the beginning of the class before we load the URL in the Java file, like this:


super.setIntegerProperty("splashscreen", R.drawable.splash);

Since the whole point of Cordova is so that you don’t have to write Java, and to promote web standards, we added these preferences to the config.xml, which should look like this:


<preference name="splashscreen" value="splash" />

The new project settings in config.xml can be found here.

Functional Testing of the Android Webview using Java: How purity was invented

A long while ago, we decided to start doing native testing of Android, mostly because we found that we were fixing the same things over and over again on Android in Java.  While the Javascript quality was higher, the Java code was generally the same as when I first wrote PhoneGap back in 2008.  So, we started with manual tests.  Then I got creative and threw in some JUnit tests back when I started working on CordovaWebView.

However, there was something that was nagging us about the manual tests.  Many of these tests required us to click on user interfaces that were implemented in HTML and Javascript.  First we tried to adapt things such as WebDriver to test this, but we found that this was extremely complex to get working on Cordova, and we only ever managed to get an abandoned branch to work with the custom CordovaWebView.  At the end this was completely unmanageable, and we abandoned this work.

However, the tickets remained, such as ones like “Automate JQTouch Tab test” or “Automate iFrame Test”.  The JQTouch one was abandoned because of these develpments, but along the way we discovered how to test the Android WebView using Java and JUnit.

The Android Test Framework gives you some very limited UI functionality tools.  These tools are designed for the Android UI and, they mostly consist of things like TouchUtils.  TouchUtils allows you to click in the middle of view like this:


touch.clickView(this, testView);

This may be super awesome for Android applications, but this sucks for things like Cordova, which is one giant view.  To prove this point, I ressurected some Canvas code that I wrote three years ago and I do some tests on it.

crap_setting

Above, you can see the click happen in the middle. It will always happen in the middle.  There is nothing that I can do to make it not happen in the middle.  This sucks.

I then googled around to see if I can get per-pixel support, and I found a blog post that showed this code:


long downTime = SystemClock.uptimeMillis();
// event time MUST be retrieved only by this way!
long eventTime = SystemClock.uptimeMillis();
Instrumentation inst = getInstrumentation();
MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, 300, 300, 0);
inst.sendPointerSync(event);

Now, this code is great, except that anyone who has done any Mobile Web Development knows that a pixel is not a pixel.  We have to factor in the screen density.  This is where purity comes in.

In purity, instead of giving the real pixels in Java, you pass in the WebKit pixels, and purity does the calculation required to do the touch where you want it.  The reason it’s called purity is because it’s simple, and it doesn’t clutter up your Javascript with event handlers and injection code.  Eventually, this may be adapted to be a plugin so that purity code can be written in Javascript, but entirely run in Java.

For example, in purity, you would call this to do a touch event:

touchTool = new Purity(testActivity, getInstrumentation());
touchTool.touch(50, 200);

OK, where is the code:

The code is in the Cordova Android test directory on my personal branch here, and it is under org.apache.cordova.test.util. It’d be awesome if someone wanted to make this a third-party plugin, especially those people who have extreme pain with UI interaction on Android.

Chrome Content View: Compilation, Comparison and Thoughts

One thing that we get asked a lot is whether Cordova should bring along its own WebKit when running on Android. The reason for this is pretty obvious to everyone at this point, especially those poor users stuck on Android 2.x. If you’re an Android 2.x user and you went to html5test.com, you would see something like this:

Yeah, that’s pretty bad, and it doesn’t get a lot better when we go to Android 4.1.

Of course, those are the WebViews that we have access to. If you compare them to Chrome:

Or you compare it with Silk on the Amazon Kindle Fire HD:

It just gets depressing. We know that it’s possible to have Webkit not suck on Android, but since the Android Team neglected the browser, we have to get desperate and do crazy things like build our own. The most reasonable candidate for us is to hack on Chromium, and the only thing that I can get building was the Chromium content view. So, I took my personal Ubuntu 12.10 machine, followed these instructions here, and after fixing a header I got this installed on my phone.

Now, that’s a good score. Sadly, this is a debug build so the performance on it is rather slow, but it does show what’s possible on mobile.  It’s actually comparable to what’s on a desktop version of Chrome minus WebGL according to this test.

However, the reality of the matter is something different.  Currently if you took the Chrome ContentView to html.adobe.com and tried to use any of the Adobe examples, the application would currently crash.

As far as us getting Cordova working on it, that’s going to take a lot of time, since the ContentView is structured very differently than the Android SDK’s WebView, and it’s not ready for primetime. Anything that we do will be a hack, and not suitable for the Android Market or anywhere else right now. Hopefully in a few month’s time, we can get something more solid and be able to have better WebViews on Android.

Advanced Tutorial: Using CordovaWebView on Android

Back on the lead-up to Cordova 2.0, we pushed for the implementation of Cordova WebView.  While this broke a lot of things, and irritated a lot of people, it seems that people are actually starting to use this new functionality.  Unfortunately, we also accidentally made a change to it in Cordova 2.2.0. In this post we step through an example that I wrote up using the existing example of the Action Bar from the Android SDK. It should be noted that this guide assumes that you are comfortable with working with Java.

You can find the example of how to use this on a GitHub repository: https://github.com/infil00p/CordovaActionView

Even though CordovaWebView does its best to try to encapsulate all the methods that are required for a working PhoneGap project, there’s still a few things that the activity that holds it has to maintain.  This is why we created the CordovaInterface. In this example, we take the default example of the ActionBar application, and we implement CordovaInterface on it.  When we start dissecting it, we see the following:

public class MainActivity extends ActionBarActivity implements CordovaInterface{
    private final ExecutorService threadPool = Executors.newCachedThreadPool();

This has to be here for the plugins to actually work. Following this, we have our typical variables both from the app, and what you’d normally find in a Cordova Activity:

    private boolean mAlternateTitle = false;
    private boolean bound;
    private boolean volumeupBound;
    private boolean volumedownBound;

    String TAG = "MainActivity-ActionBarTest";
    private CordovaPlugin activityResultCallback;
    private Object activityResultKeepRunning;
    private Object keepRunning;

    CordovaWebView mainView;

This is primarily to maintain the view, then in the create method, we basically do exactly what the old Android WebView example code does, and we find the view, and load our app:

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mainView =  (CordovaWebView) findViewById(R.id.mainView);
        mainView.loadUrl("file:///android_asset/www/index.html");
    }

Meanwhile, if you look at the XML file, you will see the FrameLayout for the main application. The ActionBar in this case is handled separately by the Android Application:


<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <org.apache.cordova.CordovaWebView 
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" 
        android:id = "@+id/mainView"/>
</FrameLayout>

When using custom widgets, you have to include the full name of the object that you want to include. It should be noted that I made a mistake here and that “match_parent” should be used instead of “fill_parent”, since “fill_parent” will be deprecated. Back in the code, we add the following methods to implement the CordovaInterface.  The first that we add is getActivity.  This is expected to get the activity that actually contains the CordovaWebView so that we can handle intents that are passed to the application.  This is pretty self-explanatory:

    @Override
    public Activity getActivity() {
        return this;
    }

After this, we implement onMessage, which deals when a message is sent from a plugin to the activity itself.  This currently exists in DroidGap, and facilitates the app plugin functionality, such as the splashscreen, the spinner, and whether the application exists.  This is not entirely necessary to implement, so in this example we simply ignore everything but exit.

    /**
     * Called when a message is sent to plugin.
     *
     * @param id            The message id
     * @param data          The message data
     * @return              Object or null
     */
    public Object onMessage(String id, Object data) {
        LOG.d(TAG, "onMessage(" + id + "," + data + ")");
        if ("exit".equals(id)) {
            super.finish();
        }
        return null;
    }

Next is the most important, which is the setActivityResultCallback code and startActivityForResult. This facilitates the passing of information from activities such as the Gallery and the Camera back to Cordova. Without this the capture API will not work, nor will any plugin that relies on another activity to start. This does the majority of the Android housekeeping:

    @Override
    public void setActivityResultCallback(CordovaPlugin plugin) {
        this.activityResultCallback = plugin;        
    }
    /**
     * Launch an activity for which you would like a result when it finished. When this activity exits, 
     * your onActivityResult() method will be called.
     *
     * @param command           The command object
     * @param intent            The intent to start
     * @param requestCode       The request code that is passed to callback to identify the activity
     */
    public void startActivityForResult(CordovaPlugin command, Intent intent, int requestCode) {
        this.activityResultCallback = command;
        this.activityResultKeepRunning = this.keepRunning;

        // If multitasking turned on, then disable it for activities that return results
        if (command != null) {
            this.keepRunning = false;
        }

        // Start activity
        super.startActivityForResult(intent, requestCode);
    }

Next is cancelLoadUrl, which was once supposed to cancel the loading of a URL. We decided to get rid of this functionality, but this operation still exists on the CordovaInterface, and will hopefully be deprecated soon. However, we still have to have it.

    @Override
    public void cancelLoadUrl() {
        // This is a no-op.
    }

The last required method are the following two at the bottom. This is the thread pool and getContext(). Both of these are expected to exist for plugins to function, however one is deprecated, and this is getContext(). Initially the CordovaInterface was once the DroidGap activity, and since an Activity inherits the properties of the context, people would just use the activity, since we can’t assume that we’re using a DroidGap activity, we need to provide an Activity. We do this with getActivity, but some people still use the old getContext() API, which is why this is still here. Eventually we will be dropping this because having two methods that return the same thing is silly.

    @Override
    public ExecutorService getThreadPool() {
        return threadPool;
    }

    @Override
    @Deprecated
    public Context getContext() {
        return this;
    }

Android Lifecycle and Results:

Now, back to actually handling the result that comes back. This is where we use the stored callback and send the result to the proper plugin. This is pretty self-explanatory as well when you look at this code. The thing is that this isn’t a part of the CordovaInterface, but instead is a part of Android. This has to be implemented if you want your Camera, Gallery and other Activity-based plugins to work.

    @Override
    /**
     * Called when an activity you launched exits, giving you the requestCode you started it with,
     * the resultCode it returned, and any additional data from it.
     *
     * @param requestCode       The request code originally supplied to startActivityForResult(),
     *                          allowing you to identify who this result came from.
     * @param resultCode        The integer result code returned by the child activity through its setResult().
     * @param data              An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
     */
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);
        CordovaPlugin callback = this.activityResultCallback;
        if (callback != null) {
            callback.onActivityResult(requestCode, resultCode, intent);
        }
    }

The other big thing is pause and resume. One of the things that we have to keep in mind is what happens to Cordova and the plugins when they pause and resume. Many of them will save their current state, and these events need to be handled. This is the most barebones code to deal with pause and resume. This does not pause any WebKit timers, so your JS will still run in the background thread, but this will handle Java states.

    @Override
    /**
     * Called when the system is about to start resuming a previous activity.
     */
    protected void onPause() {
        super.onPause();

         // Send pause event to JavaScript
        this.mainView.loadUrl("javascript:try{cordova.fireDocumentEvent('pause');}catch(e){console.log('exception firing pause event from native');};");

        // Forward to plugins
        if (this.mainView.pluginManager != null) {
            this.mainView.pluginManager.onPause(true);
        }
    }

    @Override
    /**
     * Called when the activity will start interacting with the user.
     */
    protected void onResume() {
        super.onResume();

        if (this.mainView == null) {
            return;
        }

        // Send resume event to JavaScript
        this.mainView.loadUrl("javascript:try{cordova.fireDocumentEvent('resume');}catch(e){console.log('exception firing resume event from native');};");

        // Forward to plugins
        if (this.mainView.pluginManager != null) {
            this.mainView.pluginManager.onResume(true);
        }

    }

    @Override
    /**
     * The final call you receive before your activity is destroyed.
     */
    public void onDestroy() {
        LOG.d(TAG, "onDestroy()");
        super.onDestroy();

        if (this.mainView != null) {

            // Send destroy event to JavaScript
            this.mainView.loadUrl("javascript:try{cordova.require('cordova/channel').onDestroy.fire();}catch(e){console.log('exception firing destroy event from native');};");

            // Load blank page so that JavaScript onunload is called
            this.mainView.loadUrl("about:blank");
            mainView.handleDestroy();
        }
    }

Finally, it’s important to handle any new event that appears to the application, which is what we do here with onNewIntent:

    @Override
    /**
     * Called when the activity receives a new intent
     **/
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);

        //Forward to plugins
        if ((this.mainView != null) &amp;&amp; (this.mainView.pluginManager != null)) {
            this.mainView.pluginManager.onNewIntent(intent);
        }
    }

The final result of all this is the following UI that works on Gingerbread, Honeycomb, ICS and Jellybean.

At this point, you could use fragments to have multiple CordovaWebViews, or add plugin code to manipulate the CordovaWebView so that it runs Javascript through a plugin. The reason you would want to do this is for further integration with the platform. This is clearly not for the average Cordova user, but instead for people who are comfortable with Java but still want the APIs that Cordova offers.

Shame doesn't work in Open Source

There was a fair amount of news about Android 3.0 coming out. There was tons of hype regarding the new Honeycomb release, and how it would be designed for tablets, how there is 3D Acceleration, and how the User Interface would be changed. Well, even though it’s rumoured that at Google IO, we’re all going to get tablets, we decided to go and get the Motorola Xoom so that we can have solid answers to our clients about Honeycomb tablets.

Unfortunately, we have answers, and they’re not very good with respect to Google.

First of all, the Honeycomb Emulator is so horrifically slow, we had to buy a device. The device we bought was the Motorola Xoom Wi-Fi Only model. After booting up the model, we put PhoneGap on it and ran tests. Most of the tests worked fine, however we did notice that the Native Storage (SQLite) does not work anymore and throws a security error. This is a serious problem for many PhoneGap applications that use this, and I plan on investigating the storage situation, and seeing what storage is used on the device.

Secondly, when we ran our mobile-spec test suite and ran it with no try/catch, this actually causes the browser to close. The browser shouldn’t close when a Javascript Error is thrown. The fact that you can force someone out of the browser by throwing an exception should be an indicator that this should not have been released,

Finally, this device is rumored to have 3D Acceleration, including in the browser with 3D Transforms. First, we tested the browser with the standard WebKit test here. When you test it in the actual Android Browser activity, you get the following:

Then, when you take the poster-circle.html file (which is nice and self-contained) and stick it in PhoneGap (which at this point is just an Android Webview), you get the following here:

Now, since we don’t have the source code, we have no idea why Android Webview has broken 3D CSS Transforms, but Android’s browser does. It’s clear that Android WebKit didn’t go through any sort of rigorous QA process, and was once again cobbled together. The thing that I don’t like about this situation is that I can’t see what they did to fix it on their browser. Many people would love to see 3D CSS Transforms on Android, Tablet OR Phone, but we don’t have either right now.

The thing that I don’t understand is this. If Google as a company isn’t proud enough to release this source code, then why were the proud enough to release a half-baked product? As many people know, I have been developing Android applications both with WebKit and with straight-up Java ever since I heard that the T-Mobile G1 was going to be released. I put up with flaky APIs, with WebKit bridges that would crash, and with the mess that the Android 2.0 release was. The fact that Google hasn’t learned from their mistakes with Android 2.0 was disappointing. It wasn’t too bad in 2009 when they did this, because not too many people were using Android yet, but now that we’re in 2011, and Android is on a ton of devices, and Android is in the tablet space, I’d expect there to be a little bit of consistency between the Android Browser and the WebView with respect to what is supported in WebKit.

That being said, I’d forgive flakiness in a x.0 version of Android if it came with the source code. Mainly because the community could fix the bugs and help create something kick-ass like the awesomness that Android 2.1+ was (Android 2.1 was the first solid Android version, everything else before it people liked because we were rooting for the underdog). However, today, as it stands, there’s two different versions of WebKit on the SAME DEVICE that operate differently. I think that this is a serious regression, and it’s unfortunate.

Update: I’m an idiot! The reason you don’t get 3D CSS Transforms is the fact that you have to enable 3D Acceleration for the app in the Android Manifest. A quick Google Search turned this up, and now I have it working. I still think the bug with the storage, and the fact that when you hit the back button you end up back at the First Use screen are still big reasons that Honeycomb is not ready for primetime, but WebKit has many problems, but 3D CSS Transforms aren’t one of them.

Not all cameras are equal

Recently, the way we were creating a camera and using it broke. I’m not sure why it broke, but I decided to say screw it and to use the Camera Intent in Android, because that’s what you’re supposed to do on Android anyway. This is what most Twitter Applications use, and since Twitter Apps are probably the most used application on Android, I figure if it’s good enough for them, it’s good enough for me…

Oh how wrong I was!!!

I added the new intent code, and I tested it on four phones. I tested it on the HTC EVO 4G that I received from Google IO, the Nexus One, the Motorola Milestone with the official Telus Firmware (with camera), the HTC Dream with stock Android 1.6 and the Rogers HTC Magic with Android 1.5 and the 9/11 update. Basically, everything worked but the Rogers HTC Magic. The thing is that once you use intents, you are relying on the OEMs to write a good enough Android Camera Application for you to get a picture from. This may be good for a Google blessed image, or a stable HTC phone like the EVO, but it’s clear that on certain phones from certain providers, that there may be some issues.

I’m certain that there’s phones in the wild that have broken cameras, and it’d be good to find out which phones have broken cameras. If people could test on these phones (with Canadian carriers next to them), that would be greatly appreciated:

  • HTC Hero (Telus)
  • LG EVE (Rogers)
  • Motorola DEXT (Bell)
  • Motorola Quench (Rogers)
  • Motorola Backflip (Telus)
  • Samsung Galaxy (Bell/Rogers)
  • Acer Liquid E (Rogers)
  • Xperia X10 (Rogers)

Those are the phones that I know are in the wild in Canada. I’m sure there’s more than this in other countries, namely in the United States, but this is a good cross-section of devices from a handful of manufacturers who may have their own customized camera applications. I’ve exempted test devices from this post, because I don’t think it’s fair to take a broken firmware and say “Hey, the Camera Doesn’t work!”. However, the HTC Magic should work, and it’s disappointing that it doesn’t, since this breaks not only PhoneGap’s camera capability, but anything that uses that intent. Hopefully in the future, Android cameras will be more reliable.

Using PhoneGap across ALL ANDROID DEVICES

This is my biggest pet-peeve to date. We get a lot of people trying to use PhoneGap across all devices. However, despite the work that people have done on droidgap, most people still use Eclipse as the primary way they develop with Android, because that’s what people read in the Wiki.

The problem is that when you start developing for Eclipse, you notice that PhoneGap is set to the latest version of Android. However, for some reason people want to change their target because they’re running an earlier version of Android. Since they use Eclipse to deploy their app, they are misled to believe that if you write an APK, you must target only one version.

If we’re deploying multiple APKs, PhoneGap has FAILED to do the job it was meant to do. If you have to change the target, there is something wrong!

Now, why do I say that, because I discovered this when using Eclipse:

  • Automatic Selection of your running target is EVIL!
  • Manual Selection allows you to choose your APK

The reason Automatic Selection is evil is because it will launch an Emulator and go for the highest level device it can go. Not what you’re running, but whatever the highest device is. This is the correct behaviour, but this does NOT help people who are looking to test it on their device. This causes people to instinctively mess with PhoneGap and do bad things like change the target. Here’s why you should NEVER have to change the target:



This is the line from the AndroidManifest.xml. This sets the Minimum SDK Version to 2, which is Android 1.5. A while ago, we fixed the Android 1.5 issues by changing the conditional compatibility code to look for the SDK string. We could probably do this better, and we’ll look into it in the coming weeks. However, as it stands right now, this is how we do it, and it works.

The other thing that annoys me about eclipse that I’m sure causes people to change it is this:

This is the stupidest UX ever. It should be a warning, not big red X, and this causes a LOT of headache and unnecessary gnashing of teeth. If you click OK, it will actually run on the device. As you see here, this is pointing to my Nexus One, which is still running Android 2.1-update1. I’m currently building PhoneGap for Froyo, BUT it still runs, and it works fine. This is actually how you can have one APK that runs on all devices.

I can see how someone wouldn’t want to support all Android devices, BUT given the fact that according to Google, Android 1.5 and 1.6 phones far outnumber the Android 2.x devices, it makes sense to make one APK to rule them all. The idea is to write once and deploy anywhere, and not write once and deploy to every single version of the platform. If this doesn’t work for you, you’ve found a bug, and we would appreciate it if it was filed. It’s important for PhoneGap to both run on Android 1.5 AND be able to take advantage of all the latest browser features, and the current approach we are using with the EDGE version allows us to do exactly that.

Fragmentation? The only fragmentation on Android that we care about is the fragmentation between WebKit versions, but that’s another issue entirely.

Canvas + Accelerometer on Android

Over the past month, I was working from home, and when I wasn’t busy wiping spit-up from my kid’s face, I was working on various stuff, including a new Android PhoneGap demo to replace the one that I took off the Android market. The problem with these demos is that they do not stand the test of time. However, this one should. After playing with C5Bench a couple months ago, I decided to do a quick hack of the Canvas. After many bug fixes to PhoneGap Android later, I finally managed to put together this simple example:

Now, of course, this is an early version, and the code has been thrown together very quickly, and there are bugs, which is why I haven’t posted it in the market, but you can download and try out the application here, or scan in the QR code below.

This code is based on a few examples that I found on the web of good Canvas Tutorials, namely the Breakout Clone tutorial by Bill Mill. It’s a pretty solid tutorial and shows how to effects like bounce fairly effectively. Of course, I didn’t add bounce, because I wanted more of a sliding bubble effect. I also decided to NOT use the jQuery framework to keep the javascript code as small as possible. (In fact, I didn’t even use XUI, since I didn’t see the need).

That being said, I’m definitely going to have to work on my own JS library at some point that maintains complex objects, since redrawing functions can quickly become large and cumbersome, even when using a JS library, which is better suited to the DOM and not pixel-manipulation.

So, basically you move around two objects which are directly related to each other on a screen with the accelerometer, and the method that we use is below:


var watchAccel = function()
{
var canvas = document.getElementById("canvas");
canvas.width = document.body.clientWidth;
canvas.height = document.body.clientHeight - 100;
ctx = canvas.getContext("2d");
var succ = function(a){
updateValues(a);
updateDraw(a);
};
var fail = function(){};
var opt = {};
opt.frequency = 100;
timer = navigator.accelerometer.watchAcceleration(succ, fail, opt);
}

Now, what’s interesting is how the frequency is handled. Currently, we use the setInterval to do this, exactly like the iPhone. However, this actually kinda sucks, and we may in the future move more of this into the Java land, similar to how we manage the Geolocation code that we use. However, this is good enough to create the sliding bubble effect of the application. I hope to have the final version of the app up and working before Google IO, however I’ll probably post it up to GitHub this week, feel free to try and and let me know if there’s serious issues.

Android without Eclipse

Now, for people who are Java developers, I can understand the attachment to Eclipse, but for the rest of us, Eclipse is a giant piece of bloatwear that gets in the way of the code and what we want to do with that code. However, it’s a fact of life for Android developers, or is it?

Building and running Android Applications:

Now, the first command that we deal with is the android command, which can generate a project. In typical java fashion, it takes a crap ton of flags, but you can create a project by typing this:


android create project -t 7 -k package name - a name -n name

This will create an android project. Now, on Android, the DroidGap script actually uses the Android script to create a project. So, once you have your project, what do you do with it? Well, the first thing to do is to build it, which you can do with ant. When you type ant on an Android project, you’ll get a list of commands like this:

help:
     [echo] Android Ant Build. Available targets:
     [echo]    help:      Displays this help.
     [echo]    clean:     Removes output files created by other targets.
     [echo]    compile:   Compiles project's .java files into .class files.
     [echo]    debug:     Builds the application and signs it with a debug key.
     [echo]    release:   Builds the application. The generated apk file must be
     [echo]               signed before it is published.
     [echo]    install:   Installs/reinstalls the debug package onto a running
     [echo]               emulator or device.
     [echo]               If the application was previously installed, the
     [echo]               signatures must match.
     [echo]    uninstall: Uninstalls the application from a running emulator or
     [echo]               device.

I think this is pretty self-explanatory, BUT there needs to be something said for the difference between debug versions and release versions of the same piece of software. Most of the time, you’ll want to sign the apks with a debug key, so that these are specific to your workstation. However, when releasing a project, you will want to sign it with a key in the keystore. (It’s important to take care of your keystore and not to do what I did and forget about it. This is why I haven’t gotten a free Nexus One from Google for the PhoneGap Demo Application.)

Of course, this only works either for one phone, or one emulator. What if you have multiple emulators? No problem, use adb. The Android Debug Bridge is one of the most handy tools in the Android Developers toolkit, and is extremely handy for debugging. To see what devices you have, run adb devices like this:


bowserj@shapley:~/Orbot$ adb devices
List of devices attached
0123456789012 device

To install an APK onto a device, type the following:

apk -s 0123456789012 install phonegap.apk

Debugging Javascript and Java on the Android WITHOUT ECLIPSE

Now, here’s where things get interesting. When you need to debug javascript in the latest version of PhoneGap, you can use logcat to do so, all you need to do is run adb logcat, like this:


adb logcat

Of course, to actually use a Java Debugger, such as jdb, you need to attach it to a process on the device. ADB has you covered as well, all you need to do is this:

adb jdwp

Then once you have the PID that you want, do this:

adb forward tcp:8000 jdwp: jdb -attach localhost:8000

Then you’re in! Make sure that you don’t have another process (i.e. Eclipse) running that connects to this, and you should be able to debug your Java code just like how you would debug Java code normally. I admit that I’m not a jdb/gdb ninja and things like DDD have made me dumb. Therefore, I’d appreciate any book recommendations on how to use JDB/GDB for debugging.