TurboManage

David Chandler's Journal of Java Web and Mobile Development

  • David M. Chandler


    Web app developer since 1994 and ex-Googler now residing in Peru with the wife of my youth and our three youngest children. I am working on a software development company and hoping to do more teaching as my Spanish improves. My current side project is a not-for-profit startup using GWT on AppEngine. In my "spare" time, I take pictures, preferably of Rocky Mountain National Park... or Peru.

  • Subscribe

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 220 other followers

  • Sleepless Nights…

    April 2014
    S M T W T F S
    « Mar    
     12345
    6789101112
    13141516171819
    20212223242526
    27282930  
  • Blog Stats

    • 608,344 hits

Getting Started with Java APT for Android in Eclipse

Posted by David Chandler on September 28, 2012

Fellow Googler Ian Ni-Lewis and I have recently been working on annotation-driven code generation tools for Android and I wanted to pass along a few tech notes on getting it all up and running. The tool I’m working on is a lightweight ORM for the SQLite database in the Android OS. In a nutshell, you add the @Entity to any POJO that you want to make persistable, and the annotation processor generates a corresponding DAO class and the necessary SQLiteOpenHelper.

In this post, I won’t focus on the ORM tool as it’s not quite ready, but rather on how to work with Eclipse to build an annotation processor of your own (or contribute to the ORM project once I make it available). Despite the annoyances of the Mirror API, I found it reasonably straightforward and rewarding to write my own annotation processor.

What can APT do?

Java 5 introduced an Annotation Processing Tool (apt) which can be run standalone. Eclipse 3.3 added support for annotation processing as part of the Java build process. In a nutshell, an annotation processor can find annotations in your source code, inspect the code using something like reflection, and generate new source code as a result. In addition, an annotation processor can throw errors which will show up as red squigglies in Eclipse in the original annotated source code. This is extremely powerful as it allows your annotation processor to alert the developer regarding the correct use of the annotation. For example, when you tag a POJO with @Entity, my forthcoming ORM tool shows you immediately if any field types in the POJO are unsupported.

What’s in an annotation processor?

  1. The definition of your annotations using @interface.
  2. A class that extends AbstractProcessor, part of the Java 6 annotation processing APIs. One processor class can process multiple annotations.
  3. Code that inspects the annotated source code using the Mirror API.
  4. META-INF/services/javax.annotation.processing.Processor, which contains merely the fully-qualified name of your AbstractProcessor class, like “com.example.storm.MainProcessor”.

How to run your annotation processor

To use your annotation processor, package it in a jar. There are several ways to run it:

  1. On the command line, run Java apt. In Java 6 and later, javac will automatically search the classpath for annotation processors. You can bypass the default discovery mechanism using the -processor and -processorpath compiler options. You can also include your own AnnotationProcessorFactory to replace the default factory.
  2. In ant, add the -processorPath and -processor options or use the ant apt task (pre-Java 6).
  3. In Eclipse, add your annotation processor jar to the annotation factory classpath as described in the Eclipse guide to APT .

While the Eclipse JDT-APT integration is cool as it enables editor integration (hello, red squigglies), there is one limitation that makes it a pain to work on the annotation processor code itself. Whether by design or bug, when you make changes to your annotation processor, you must repackage as a jar and manually remove / add it to the annotation factory classpath of any projects using it. The packaging can be easily automated as I will show, but I haven’t yet found a way to get Eclipse to pick up changes to apt jars, even when they’re referenced as jars in an Eclipse project (vs. external jars).

Getting Started

During development, I found it useful to organize the annotation processor code into 3 separate projects: API, impl, and test.

The API project

The API project contains the @interface definitions for your annotations. Since this code will need to be on the classpath of any project that uses your annotations, it’s reasonable to also include other non-generated code that will be used at runtime. For example, my API project includes a DAO base class and other runtime code as well as the annotations. Since some of the runtime code has Android dependencies, I made this an Android library project by checking the Library box when running the New Android Application Project wizard. The project has no Activities, and the AndroidManifest.xml contains only the <uses-sdk> element.

As we noted earlier, the only way to run an annotation processor in Eclipse is from a jar or plugin. Since the API is required by the annotation processor, it must exist as a jar on the annotation factory classpath of any client projects such as the test project below. Therefore, it’s helpful to build the jar every time you make a change to the project. Eclipse does not do this for you automatically. However, you can set it up using ant as follows:

Once you’ve created the API project and configured the build path as required, export an ant build file using File | Export | Ant Buildfiles.

Edit the build.xml and add this inside the build-project target:

<jar destfile="your-api.jar" basedir="bin/classes"></jar>

Go to project properties | Builders and add a New Ant Builder. In the Main tab, click Browse Workspace… to choose the build.xml file, then finish. The default targets are OK. Now every time you save a change to the API, you’ll see it build your-api.jar in the project.

The APT implementation project

The impl project includes one or more AbstractProcessors, supporting model classes, and the META-INF file that specifies the name of your processor class. The APT impl project has no Android dependencies because the Android references exist only in the Freemarker templates. This project has on its build path the API project. You could depend on the API jar since it’s getting updated by your ant task, but depending on the project will facilitate refactoring. As for the API project, you’ll want to use an Ant Builder to update the impl jar every time the project is built.

My annotation processor uses the Freemarker template language to generate source code. The basic approach is to inspect the annotated code, populate a model class (like EntityModel) which simply has getters and setters for the fields that will be needed by the template, then invoke Freemarker, passing it the model and the template. This is my annotation processor:

package com.example.storm;

import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.JavaFileObject;

import freemarker.cache.ClassTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

@SupportedAnnotationTypes({ "com.example.storm.Entity","com.example.storm.Database" })
@SupportedSourceVersion(SourceVersion.RELEASE_6)
public class MainProcessor extends AbstractProcessor {
	private ProcessorLogger logger;
	private Configuration cfg = new Configuration();
	private List entities = new ArrayList();

	@Override
	public boolean process(Set<? extends TypeElement> annotations,
			RoundEnvironment roundEnv) {
		this.logger = new ProcessorLogger(processingEnv.getMessager());
		logger.info("Running MainProcessor...");

		cfg.setTemplateLoader(new ClassTemplateLoader(this.getClass(), "/res"));

//		for (TypeElement annotationType : annotations) {}

		for (Element element : roundEnv.getElementsAnnotatedWith(Entity.class)) {
			Entity annotation = element.getAnnotation(Entity.class);
			EntityModel em = new EntityModel(element);
			processTemplateForModel(em);
			// retain for DatabaseHelper class
			entities.add(em);
		}

		for (Element element : roundEnv.getElementsAnnotatedWith(Database.class)) {
			Database dbAnno = element.getAnnotation(Database.class);
			DatabaseModel dm = new DatabaseModel(element, dbAnno.name(), dbAnno.version());
			// Add entity DAOs
			for (EntityModel em : entities) {
				dm.addDaoClass(em.getQualifiedClassName());
			}
			processTemplateForModel(dm);
		}

		return true;
	}

	private void processTemplateForModel(ClassModel model) {
		JavaFileObject file;
		try {
			file = processingEnv.getFiler().createSourceFile(model.getQualifiedClassName());
			logger.info("Creating file  " + file.getName());
			Writer out = file.openWriter();
			Template t = cfg.getTemplate(model.getTemplatePath());
			logger.info("Processing template " + t.getName());
			t.process(model, out);
			out.flush();
			out.close();
		} catch (IOException e) {
			logger.error("EntityProcessor error", e, model.getElement());
		} catch (TemplateException e) {
			logger.error("EntityProcessor error", e, model.getElement());
		}
	}

}

The hardest part about using Freemarker was locating the templates on the classpath. I found it is easiest to use Freemarker’s ClassTemplateLoader and put my .ftl templates in src/res. The name happens to coincide with the standard Android resources folder; however, this is not required as the impl project is not an Android project. Furthermore, my res folder is under src, not a sibling directory as the standard Android folder. This is the easiest way for ClassTemplateLoader to find it.

Note the catch clauses in processTemplateForModel() that invoke logger.error(). Messages written to the ProcessorLogger show up in Eclipse’s Error Log view. In addition, by passing the Element which triggered the error, Eclipse can generate red squigglies in source code using the annotation.

In my current design, EntityModel and DatabaseModel correspond to the @Entity and @Database annotations and extend ClassModel, which does the heavy lifting using the Mirror API. Here are the key methods from ClassModel which show how to introspect on an annotated class and its fields using the Mirror API:

	public ClassModel(Element element) {
		TypeElement typeElement = (TypeElement) element;
		this.typeElement = typeElement;
		readFields(typeElement);
	}

	protected void readFields(TypeElement type) {
		// Read fields from superclass if any
		TypeMirror superClass = type.getSuperclass();
		if (TypeKind.DECLARED.equals(superClass.getKind())) {
			DeclaredType superType = (DeclaredType) superClass;
			readFields((TypeElement) superType.asElement());
		}
		for (Element child : type.getEnclosedElements()) {
				if (child.getKind() == ElementKind.FIELD) {
					VariableElement field = (VariableElement) child;
					Set modifiers = field.getModifiers();
					if (!modifiers.contains(Modifier.TRANSIENT) && !modifiers.contains(Modifier.PRIVATE)) {
						String javaType = getFieldType(field);
						addField(field.getSimpleName().toString(), javaType);
					}
				}
		}
	}

	protected String getFieldType(VariableElement field) {
		TypeMirror fieldType = field.asType();
		return fieldType.toString();
	}

I’m not completely happy with this design and plan to move all the mirror API code into processor classes, leaving the model classes pure. This should enable even more fine-grained error reporting. Here’s a bit of my Freemarker template src/res/EntityDao.ftl. All variable names inside ${} invoke the corresponding getters in the model class passed to the process() method above.

public class ${className} extends ${baseDaoClass}<${entityName}>{

	public static void onCreate(SQLiteDatabase db) {
		String sqlStmt =
			"CREATE TABLE ${tableName}(" +
				<#list fields as field>
				"${field.colName} ${field.sqlType}<#if field.primitive> NOT NULL<#if field_has_next>," +
				</#list>
			")";
		db.execSQL(sqlStmt);
	}
	...
}

The test project

The test project is an Android Application Project which has on its build path the API project. However, because the API project is an Android Library project, you must add it as a referenced library under project properties | Android, not the usual Java Build Path. In addition, you must add 3 jars to the annotation factory classpath in Eclipse: the Freemarker jar, the API jar, and the impl jar.

There are several ways to invoke Android unit tests. I found it easiest to include test instrumentation directly in an Android Application Project created using the Application Project wizard (not the Android Test Project wizard, as that requires yet another project under test). It has the default MainActivity, and you can simply add the test instrumentation to AndroidManifest.xml as follows:

    <instrumentation
        android:name="android.test.InstrumentationTestRunner"
        android:targetPackage="com.example.storm.test" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/title_activity_main" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <uses-library android:name="android.test.runner" />
    </application>

The activity should already be there; you just need to add the uses-library tag and the instrumentation tag pointing to the package which contains your Junit 3 tests (note: Android doesn’t use Junit 4). To create tests, simply run the New Junit Test wizard. To run them, right-click on the project and select Run As | Android Junit Test. This will run the test on an emulator or device and show results in the standard JUnit console.

Wrapping up

Creating an annotation processor has been a pretty fun learning project, and I trust the final product will be useful to a lot of Android developers. The most painful part is having to manually remove and re-add the jars from the test project’s annotation factory classpath every time I make a change to one of the jars. I have to go to project properties | Java Compiler > Annotation Processing > Factory Path, uncheck the boxes next to the api and impl jars, click OK and rebuild, then go back in to recheck the boxes and rebuild. Doesn’t take long with keyboard shortcuts, but still… I’ll be glad when then the ORM jars are stable, and (I hope), so will you.

Posted in Android, Eclipse | 6 Comments »

Accessible Fibonacci app

Posted by David Chandler on September 7, 2012

Fibonacci series calculator with plus / minus buttonsAs I wrap up my trip to DC to present at the GDG meetup (with huge turnout ~200: thanks, everyone!), I thought I would take my own medicine and update my Fibonacci app to make it more accessible. The main improvement was to add a couple of buttons to the Series tab which are much easier to use with TalkBack than the slider bar.

In addition, I added some <android:contentDescription> tags to assist the screen reader. Here is the latest source code and the app in the Google Play Store.

Call me a geek, but I get a kick out of uploading new APKs to the Google Play Store while on the plane.

Enjoy!

Posted in Android | Leave a Comment »

Android Accessibility Notes

Posted by David Chandler on September 7, 2012

This week I spoke at the FCC event on Developing with Accessibility and wanted to post a couple notes here for the benefit of Android users and developers alike.

JellyBean offers a lot of built-in features for accessibility, including TalkBack with Explore by Touch, large text (which makes my phone usable when I don’t have my glasses handy), and support for external input devices including keyboards, D-pad controllers, and Braille displays.

At the conference, I got good feedback from low-vision users on the TalkBack feature preloaded on JellyBean phones, particularly the new way of using Explore by Touch where you can double tap anywhere on the screen to activate the currently selected button or control. Another helpful feature is the new global gestures that let you go Home, Back, Recent Apps, or Open Notifications from any app. Google Voice Actions and Google Now are also helpful; unfortunately, there are some bugs which make it difficult to use voice actions with TalkBack. If you want to give it a try with TalkBack, use a two-finger slide-up gesture to launch Google Now.

If you’re an Android developer, you might be surprised how little effort is required to make your app accessible to low-vision and/or low-dexterity users. The basic idea is to make all controls in your app both readable and navigable. To do the former, you can add <android:contentDescription> elements in your XML layouts or call setContentDescription() programmatically on any View. Navigation is also easy. Most standard widgets are Focusable, which allows swipe up/down/left/right to move focus between controls in the UI. If you’re using a custom view or one that is not accessible, you can set <android:focusable=”true”> in your layout XML. In addition, you can set <android:nextFocusUp/Down/Left/Right> to give Explore by Touch hints on where to move focus when used with the swipe gestures, an external D-pad, or software D-pad controller.

Google has published two new resources for developers and testers. These are excellent starting points for making your Android apps accessible:
Accessibility Developer Checklist
Accessibility Testing Checklist

JellyBean also offers a rich API for building accessibility services like TalkBack. For more info, see the doc on Building Accessibility Services. JellyBean also offers limited support for closed captioning in the MediaPlayer component. In a nutshell, you call addTimedTextSource() to load the closed captioning data file, then selectTrack() to enable it during playback.

If you’re an Android developer and have never tried to use your apps with TalkBack or an external keyboard, give it a shot! A few simple changes can make your app useful to many more users, and any changes you make as a result will likely improve the app for everyone.

Posted in Android | Tagged: , | 1 Comment »

The History and Future of Google Web Toolkit

Posted by David Chandler on July 11, 2012

I’ve eagerly anticipated this blog post. There is a lot I have wanted to say about GWT in the past year, and Ray Cromwell says it all in this candid and optimistic Google I/O session.

Highlights

  • There are over 100k active GWT developers world-wide
  • GWT 2.5 RC1 is now available with many code size improvements and some long-awaited new features (SourceMaps, SuperDevMode, and Elemental)
  • Google is moving from gatekeeper to peer among equals on the newly formed GWT steering committee
  • GWT trunk is now open for commits by external parties (no Googler intervention required)
  • Sencha has released GXT 3, a major refactoring built on true GWT
  • Vaadin will be offering commercial support for GWT
  • Mgwt is awesome (Mobile GWT, works with Phonegap)

Markers

  • 12:05 Introducing SourceMaps and SuperDevMode
  • 25:40 Future of GWT
  • 29:45 Michael Mullany, Sencha
  • 39:58 Joonas Lehtinen, Vaadin
  • 49:30 Q&A

Summary

I think it’s obvious to everyone that the GWT team at Google has shrunk significantly over the last year; nevertheless, GWT 2.5 demonstrates that GWT is still moving forward at Google as well as in the open source community. I think enterprises will be especially interested in Vaadin’s first-ever commercial support for GWT, and Sencha GXT customers will likewise be glad to see Sencha on the GWT steering committee. As a mature framework, GWT may not attract the attention and resources associated with the Next Big Thing, but at the same time, GWT 2.5 is better than ever for building large-scale rich Web apps and cross-platform mobile apps in the enterprise.

Posted in Google Web Toolkit | 1 Comment »

A basic HTTP client for Android (and more)

Posted by David Chandler on June 12, 2012

TL;DR http://code.google.com/p/basic-http-client/

Last year, the Android team recommended the use of java.net.HttpURLConnection instead of Apache HttpClient for Gingerbread and up. Unfortunately, HttpURLConnection is a lower-level API, so now everyone has to do their own URL encoding, set MIME type application/x-www-form-urlencoded, read InputStream and ErrorStream, wrap with try/catch, finally close streams, etc.

Rather than write all that code one-off for each request, I’ve created a basic HTTP client which lets you easily

  • make GET, POST, PUT, and DELETE requests
  • make asynchronous requests with automatic retries and exponential backoff
  • customize requests using a RequestHandler
  • automatically wrap requests in an AsyncTask (Android-specific)

It has a very simple API, and the jar weighs in at only 40kB (basic) or 45kb (Android), including source. It is Android-independent by design, although Android developers will find it especially useful.

Basic usage

    // Example code to login to App Engine dev server
    public void loginDev(String userEmail) {
        BasicHttpClient httpClient = new BasicHttpClient("http://localhost:8888");
        ParameterMap params = httpClient.newParams()
                .add("continue", "/")
                .add("email", userEmail)
                .add("action", "Log In");
        httpClient.addHeader("someheader", "value");
        httpClient.setConnectionTimeout(2000); // 2s
        HttpResponse httpResponse = httpClient.post("/_ah/login", params);
        System.out.println(httpResponse.getBodyAsString());
    }

    // Example code to log in to App Engine production app with an auth token
    // from Android's AccountManager
    public void loginProd(String authToken) {
        BasicHttpClient httpClient = new BasicHttpClient("http://localhost:8888");
        ParameterMap params = httpClient.newParams()
                .add("auth", authToken);
        HttpResponse httpResponse = httpClient.get("/_ah/login", params);
    }

Make an asynchronous request

        AndroidHttpClient httpClient = new AndroidHttpClient("http://192.168.1.1:8888");
        httpClient.setMaxRetries(5);
        ParameterMap params = httpClient.newParams()
                .add("continue", "/")
                .add("email", "test@example.com")
                .add("action", "Log In");
        httpClient.post("/_ah/login", params, new AsyncCallback() {
            @Override
            public void onComplete(HttpResponse httpResponse) {
                System.out.println(httpResponse.getBodyAsString());
            }
            @Override
            public void onError(Exception e) {
                e.printStackTrace();
            }
        });

To make an asynchronous request, you invoke the request methods (get, post, etc.) with an additional argument, an AsyncCallback, which can be easily implemented in an anonymous inner class as shown above. Here’s a quick tour of the various clients you can use.

BasicHttpClient

BasicHttpClient has no Android dependencies so it can be used on any platform which provides java.net.HttpURLConnection. It offers a synchronous interface only via get, post, put, and delete methods. Note that there are two post methods, one for posting form data (a ParameterMap) and one for uploading content of any type you specify. If you prefer, you can make a new HttpGetRequest and execute() it instead of using the get() method. In fact, all the request methods do this under the covers.

AndroidHttpClient

AndroidHttpClient extends both AbstractHttpClient and AsyncHttpClient so it can used synchronously or asynchronously. Remember that you should not invoke the immediate (non-async) methods on the UI thread. Android will throw an exception if you do. Besides automatically wrapping requests in an AsyncTask via the async methods, AndroidHttpClient automatically includes the workaround for a major bug in HttpURLConnection in earlier versions of Android as discussed in the Android Developers blog post above.

Cookie management

AbstractHttpClient (the base class for everything) registers a default java.net.CookieManager that is used by all HttpURLConnection requests in your VM (= app on Android). The default CookieManager acts just like a browser, remembering cookies it receives and sending them on subsequent requests. You shouldn’t need to set or read cookie headers manually at all. In fact, you can’t. When the CookieManager is in use, it consumes the cookie headers.

Under the covers

AbstractHttpClient is the base client from which all the others flow. It implements a synchronous API and can be instantiated using an anonymous inner class if you just want the base functionality: new AbstractHttpClient() {}.

AsyncHttpClient adds an asynchronous API where each request method takes an extra callback argument. It is intended to be extended like AndroidHttpClient. Subclasses should provide a platform-specific wrapper for async requests. AndroidHttpClient provides an AsyncTask wrapper that AsyncHttpClient uses to make requests in the background.

BasicHttpClient and AndroidHttpClient both delegate the actual I/O to a BasicRequestHandler, which implements a simple request lifecycle (open, prepare, write, read, error). You can construct any of the clients with a custom RequestHandler. BasicRequestHandler is abstract so you can easily override only one method using an anonymous inner class. This is shown on the project home page. A common use for this may be to provide your own onError() method which determines whether a given error condition is recoverable for your application.

Testing

There are no automated tests yet because I haven’t made the effort to simulate connections, timeouts, etc. I have done considerable manual testing, however, of the async capabilities with retries. The basic recipe is as follows:

  • Try an async request to an unreachable IP address (say, 10.0.0.1 or 192.168.1.1). This lets you observe connection timeouts and retries.
  • Copy the SleepServlet in the test package to a Web project and add the servlet mapping in web.xml. Start the server and try an async request. This lets you observe read timeouts and retries.
  • Try an async request to a functioning URL and observe success.

Summary

The code is copiously commented with hopefully non-trivial observations about function and intended use. Planned enhancements include a MappingJsonClient which can take POJO arguments instead of raw bytes or Strings. Spring for Android already has a nice RestTemplate, but like Apache HttpClient, is fairly heavyweight on account of its configurability.

Enjoy!

Posted in Android | 66 Comments »

Troubleshooting App Engine-connected Android projects with c2dm

Posted by David Chandler on May 18, 2012

Google Plugin for Eclipse has a wizard to create an Android project with App Engine back end including client push (c2dm). The official tutorial is quite good, but after spending the better part of a day trying to get the Cloud Tasks sample up and running again, I thought it might be useful to post a few tips.

General Tips

  • Sign up for c2dm first. Remember the package name and use it when running the Eclipse wizard! The package name is required, and once you choose the package name on c2dm sign-up, it is nowhere visible later. Be patient–it may take an hour or even a day to activate your account.
  • Sign in to Eclipse with the c2dm account name you’ll use (see lower left corner–if not visible, you need Google Plugin for Eclipse). It’s easy to forget this, but Debug As | Local App Engine Connected Project requires you to be signed in.

Run on a Phone With the GAE Dev Server

In this scenario, the phone and dev server must be on the same network! Easiest way is to connect to the same wi-fi router. USB cable does nothing. Be aware that most public wi-fi routers don’t allow devices to contact each other, so it will probably work best at home or on your company’s guest wi-fi network.

  • Ensure that phone and dev server are on the same wi-fi network. Disconnect both from any VPNs.
  • Add -bindAddress 0.0.0.0 to your Web project’s Run Configuration | Program Arguments. This will start the server listening on all addresses, not just the default localhost (which the phone can’t see).
  • When you choose Debug As | Local App Engine Connected Android Application, GPE hardcodes your machine’s IP address in assets/debugging_prefs.properties. This is where the Android app looks up the address of the server.
  • You can launch/debug the Android app and the Web app independently; however, if your server IP address changes, you must again Debug As | Local App Engine Connected Android Application in order to update the IP address in assets/debugging_prefs.properties.
  • In case you wondered, the Android and Web projects are associated in a file in the Android project. You can find it in .settings/com.google.gdt.eclipse.mobile.android.prefs. To associate a different App Engine project with an Android project, simply edit this file and refresh the project.
  • If you’re using the GWT dev mode browser plugin, you can still connect to 127.0.0.1. If you connect to the address shown in Development Mode tab (your machine’s network IP address), you may need to allow the address in the dev mode browser plugin. Click the GWT icon in the address bar to do this.
  • Make sure you log in to the Web app as the c2dm user, not the default test@example.com.

Run on a Phone Against the Production App

In the production scenario, you’re using real c2dm so the phone doesn’t have to be on wi-fi at all.

  • Edit Setup.java and change APP_NAME and SENDER_ID to match your GAE app id and c2dm account.
  • Change app id in appengine-web.xml to match your GAE app.
  • Deploy to App Engine with your c2dm account.
  • Force sign in to GAE app by going to [prod_url]/tasks/. This triggers the security constraint in web.xml to get logged in to GAE. After logging in, you’ll get an error page, but that’s OK. Then go to [prod_url]/ and Say Hello to App Engine. If logged in, you should see a success message.
  • If you’ve previously connected an account on a phone to this production app, go to GAE datastore viewer and delete all records.
  • In Eclipse, Debug as | Remote App Engine Connected Android project
  • On the phone, you’ll be prompted to connect an account. Use your c2dm account. If you have previously connected a different account, go to Menu | Accounts | Disconnect in the app and reconnect.

The CloudTasks project still has a few issues. Feel free to log them in the tracker.

Posted in Android, AppEngine, Google Web Toolkit | 7 Comments »

Show soft keyboard automatically when EditText receives focus

Posted by David Chandler on May 2, 2012

I’ve been unpleasantly surprised at how difficult it is to find info on showing or hiding the Android soft keyboard, so I’m putting a few code snippets out here for posterity.

Problem

I have a DialogFragment with an EditText. When the dialog is shown, I want to immediately focus the EditText and show the keyboard.

Solution 1 (recommended)

Set the dialog Window’s soft input method.

public class EditNameDialog extends DialogFragment {

	private EditText editText;

	public EditNameDialog() {
		// Empty constructor required for DialogFragment
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		View view = inflater.inflate(R.layout.fragment_edit_name, container);
		editText = (EditText) view.findViewById(R.id.txt_yourName);

		// Request focus and show soft keyboard automatically
		editText.requestFocus();
		getDialog().getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE);

		return view;
	}
}

As an alternative to editText.requestFocus(), you can use the <requestFocus /> tag in the fragment’s XML layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/edit_name"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/lbl_yourName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="What is your name?" />

    <EditText
        android:id="@+id/txt_yourName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10" >
		<requestFocus />
    </EditText>

</LinearLayout>

Setting the Window’s soft input method is definitely the easiest way to show the keyboard. However, in some circumstances, you may need to “force” it open or shut by invoking the InputMethodManager directly.

Solution 2

Invoke the InputMethodManager service.

This approach is more complicated because the input method manager ignores keyboard requests unless the EditText and the Window it’s in both have focus. So upon entering an Activity / Dialog, you need to wait until focus has settled down before you request the keyboard. You can do this by calling the InputMethodManager service in an OnFocusChangeListener, but Views can get focus before the Window itself does, so you have to wait for Window focus. There is no way that I can find to add an OnFocusChangeListener on the Window object itself, but listening for View focus and posting a Runnable seems to work:

...
		editText.setOnFocusChangeListener(new OnFocusChangeListener() {
			@Override
			public void onFocusChange(View v, boolean hasFocus) {
				editText.post(new Runnable() {
					@Override
					public void run() {
						InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
						imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT);
					}
				});
			}
		});
		editText.requestFocus();
...

This solution is not recommended because it may be buggy, but illustrates using post() to wait for the UI to settle, which may be useful in other circumstances. Note that this solution won’t work with the requestFocus tag in the layout XML because in that case, the EditText receives focus before the OnFocusChangeListener has been registered. Therefore, in the example above, we programmatically request focus after adding the listener.

Bad solutions

You can set the attribute android:windowSoftInputMode=”stateVisible” for your activity in AndroidManifest.xml. However, in the case of a DialogFragment, that will show the keyboard in the Activity’s window, which is behind the Window associated with the Dialog in the DialogFragment.

In order to get around possible Window / View focus bugs, you can use postDelayed() with a number of milliseconds to post a Runnable; however, hard-coded delays are never recommended because they may introduce unpredictable behavior under different conditions / different devices.

Summary

Ordinarily, the soft keyboard default behavior should be sufficient; however, when you programmatically focus on an EditText, you can set the Window’s soft input method to show the keyboard.

Posted in Android | 11 Comments »

Enable Geolocation in a WebView (Android)

Posted by David Chandler on April 23, 2012

HTML5 Geolocation lets you access the browser’s location information from Javascript. For a quick demo, visit google.com in a mobile browser and observe your location at the bottom of the page. Geolocation works “out of the box” in the Android browser or Chrome Beta for Android. The first time you visit a Web site that wants to know your location, the browser will prompt you to allow it.

However, if you’re writing an Android app that uses a WebView to display Web content, you must specifically enable geolocation in the WebView in order for pages that use it to work properly. To illustrate, I’ve put together a minimal Android app that uses a WebView with geolocation enabled. The easiest way to use the sample is to create a new Android Project called GeoWebView (package name com.example.webview) and then copy and replace the generated sample code with the files below.

First, the Android manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.webview"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="5" />

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".GeoWebViewActivity"
            android:label="@string/app_name"
            android:theme="@android:style/Theme.NoTitleBar" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Only two permissions are required: INTERNET and ACCESS_FINE_LOCATION. This example uses the NoTitleBar theme to display the WebView content full screen.

Next, our layout (main.xml):

<?xml version="1.0" encoding="utf-8"?>
<WebView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/webView1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" />

Not much to it, just a WebView.

And finally, here is the complete app, consisting only of GeoWebViewActivity:

package com.example.webview;

import android.app.Activity;
import android.os.Bundle;
import android.webkit.GeolocationPermissions;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;

/**
 * A minimal WebView app with HTML5 geolocation capability
 *
 * @author David M. Chandler
 */
public class GeoWebViewActivity extends Activity {

	/**
	 * WebViewClient subclass loads all hyperlinks in the existing WebView
	 */
	public class GeoWebViewClient extends WebViewClient {
		@Override
		public boolean shouldOverrideUrlLoading(WebView view, String url) {
			// When user clicks a hyperlink, load in the existing WebView
			view.loadUrl(url);
			return true;
		}
	}

	/**
	 * WebChromeClient subclass handles UI-related calls
	 * Note: think chrome as in decoration, not the Chrome browser
	 */
	public class GeoWebChromeClient extends WebChromeClient {
		@Override
		public void onGeolocationPermissionsShowPrompt(String origin,
				GeolocationPermissions.Callback callback) {
			// Always grant permission since the app itself requires location
			// permission and the user has therefore already granted it
			callback.invoke(origin, true, false);
		}
	}

	WebView mWebView;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		mWebView = (WebView) findViewById(R.id.webView1);
		// Brower niceties -- pinch / zoom, follow links in place
		mWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
		mWebView.getSettings().setBuiltInZoomControls(true);
		mWebView.setWebViewClient(new GeoWebViewClient());
		// Below required for geolocation
		mWebView.getSettings().setJavaScriptEnabled(true);
		mWebView.getSettings().setGeolocationEnabled(true);
		mWebView.setWebChromeClient(new GeoWebChromeClient());
		// Load google.com
		mWebView.loadUrl("http://www.google.com");
	}

	@Override
	public void onBackPressed() {
		// Pop the browser back stack or exit the activity
		if (mWebView.canGoBack()) {
			mWebView.goBack();
		}
		else {
			super.onBackPressed();
		}
	}
}

The onCreate() method obtains the WebView and enables Javascript and pinch/zoom. The last few lines before loading the URL google.com are the most important. In addition to calling setGeolocationEnabled(true), we configure the WebView by passing it two kinds of “clients”: a chrome client, which handles UI, or “chrome”, events (no relation to the browser bearing that name) for your WebView, and a basic client, which handles content-related events such as errors and form resubmission.

First, let’s look at the WebViewClient as implemented in the inner class GeoWebViewClient. It’s not strictly necessary for geolocation, but does something that almost all WebView apps do, which is to load any new URLs (such as when the user touches a hyperlink) in the same WebView. The default behavior is to fire an Intent to load in another browser, which is rarely what you want.

Next, a WebChromeClient as implemented in GeoWebChromeClient is essential for geolocation to work in the WebView. Whenever the WebView encounters Javascript using the Geolocation API, the WebView calls the method onGeolocationPermissionsShowPrompt() in its associated WebChromeClient. The name of the method is slightly misleading in this context, as neither the WebView nor the WebChromeClient actually shows a prompt. If you want to show a prompt, this is the place to do it, and you can find an example in the AOSP source code for packages/apps/Browser/src/com/android/browser/Tab.java. Fortunately, since the app itself declares the ACCESS_FINE_LOCATION permission, the user has effectively already granted permission, and you can simply invoke the callback with the second argument (allow) == true.

The final touch on our app is to wire up the phone’s back button in the onBackPressed() method. If we can go back in the WebView, we do that; otherwise, we back out of the app altogether.

Thanks to Roman Nurik and several others on StackOverflow for your helpful past answers on this topic.

Posted in Android | Tagged: , , | 9 Comments »

App Engine, Dart, and Android at DevNexus

Posted by David Chandler on March 23, 2012

DevNexus keynote

DevNexus keynote

First, a huge thank you to the volunteer organizers and sponsors of DevNexus! The Atlanta JUG‘s annual not-for-profit conference attracted 500 mostly Java developers this year and remains one of the best values of any developer conference in the world.

I gave an update on Google App Engine for Java (see slides) and a pitch for HTML5 + Dart (see slides).

There were a lot of talks on mobile / Web development this year, including:

  • JQuery Mobile framework (Raymond Camden, Adobe)
  • Intro to PhoneGap (Raymond Camden, Adobe)
  • Java-Powered Mobile Cross-Platform Mobile Apps with Phone Gap (Andrew Trice)
  • Web vs. Apps keynote (Ben Galbraith)
  • Easy Mobile Development: Intro to Appcelerator Titanium (Pratik Patel)
  • What’s New in Android (Robert Cooper)
  • Spring for Android (Roy Clarkson, Spring)
  • Mind-Blowing Apps with HTML5 Canvas (David Geary)

All the mobile / Web talks that I attended were standing room only (70-130 people, depending on room capacity). It seems that mobile in the enterprise is red hot and enterprise apps are good candidates for Web apps vs. native. I was particularly impressed with

Thanks again to Gunnar, Vince, Sudhir, and the gang for making DevNexus such a high-quality event.

Posted in Android, AppEngine, Dart | 6 Comments »

Is the mobile Web ready for business app developers?

Posted by David Chandler on March 15, 2012

Disclaimer: these thoughts are my own, not necessarily those of my employer.

I recently attended A Night with Sencha and Ted Patrick, and it got me thinking more about the mobile web. Mobile developers are clearly hungry for cross-platform solutions like Sencha and Titanium, and HTML5 promises significant cross-platform compatibility. (Action game developers, you can stop reading now because you already know that the high-performance mobile Web is not there yet. In fact, many folks I talked to last week at GDC are not even using the Android SDK, but rather the Android Native Development Kit to port games from iOS in C.)

Having said that, the mobile web for business app developers is arguably the easiest way to develop mobile apps, period, even without the side benefit of cross-platform compatibility. Why?

  • Web development frameworks is a rich and mature space. There are dozens of well-established popular frameworks on both client and server for MVC, CSS, JSON, etc. We’ve been doing Web development for almost 20 years now.
  • Web design tools abound. Although IDEs for native apps offer design & layout functionality, more designers are familiar with tools like Dreamweaver for HMTL+CSS. Firebug and Chrome DevTools are the ultimate WYSIWYG editors. Who wants to learn another style language when you’ve finally conquered CSS (kicking and screaming)?
  • Mobile browsers, like their desktop cousins, offer great tools for design and debugging (such as Safari Web Inspector and remote debugging with Chrome Beta for Android). Tools like the Window Resizer Chrome extension let you quickly test your app in a variety of different resolutions.
  • Frameworks like Sencha do a lot of the heavy lifting around RPC, local storage, dynamic UI creation & data binding. These things take a lot of work to do correctly in a native app.
  • You don’t have to worry as much about device compatibility. Mobile browsers aren’t perfect and there are still compatibility gaps (see mobilehtml5.org), but most players in the ecosystem are motivated to ensure that the browser runs well on all devices. The ecosystem is probably less concerned with your apartment finder app. Provided you’re using standard browser features, the browser vendor bears much of the testing burden.

So why does anyone write native apps?

  • Monetization, of course. But you can wrap your app in a WebView. As far as I know, WebViews aren’t an issue in any of the app markets with the possible exception of Apple, and according to Ted Patrick, Apple has been good about letting WebView apps in “once they get to know you and find that your app is reliable.” YMMV.
  • Native look and feel. Sencha / jqTouch does a convincing job with this on iOS. I haven’t seen it on Android.
  • Performance. I already mentioned this with respect to fast-moving games, but most business apps don’t use Canvas or a lot of CSS transitions. And with care, even large apps that manage a lot of data (like mobile GMail for the Web) can be snappy.
  • Hardware access. With HTML5, you can get the user’s location and even the accelerometer, but not the camera. At least not yet. But for most business apps, location is all you need.
  • Integration with the OS. If your app needs a ContentProvider or background Service or handles Intents, then you do indeed need a native app. Several well-known apps are succeeding with a hybrid approach, however, by using WebViews for rendering and native Services for data access. This simplifies the UI design as noted earlier while retaining other advantages of the platform.
  • Finally, native apps let you write code in something other than Javascript. Of course, you could try GWT or Dart and compile to JS, too. Ironically, many of the native cross-platform solutions also require you to write your app in Javascript.

Over the next few weeks, I’ll be porting my listwidget app to native Android and mobile Web using a variety of technologies. I’ll keep you posted.

Posted in Android, Dart, Google Web Toolkit | Tagged: , | 1 Comment »

 
Follow

Get every new post delivered to your Inbox.

Join 220 other followers

%d bloggers like this: