TurboManage

David Chandler's Journal of Java Web and Mobile Development

  • David M. Chandler


    Web app developer since 1994 and former Developer Advocate with Google now residing in Colorado. Besides tech, I enjoy landscape photography and share my work at ColoradoPhoto.gallery.

  • Subscribe

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

    Join 231 other followers

  • Sleepless Nights…

    December 2018
    S M T W T F S
    « Nov    
     1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031  
  • Blog Stats

    • 965,039 hits

Archive for the ‘Android’ Category

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.

Advertisements

Posted in Android | Tagged: , | 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 | 70 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 | 15 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: , , | 28 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 »

Getting Started with Android

Posted by David Chandler on February 7, 2012

Fibonacci Series for Android

I’ve recently joined the Android Developer Relations team at Google and am thus renaming this blog David Chandler’s Journal of Java Web and Mobile Development. Some of my favorite Google platforms are intersecting in new ways all the time (witness today’s announcement of Chrome Beta for Android ICS). Having done Web development for 18 years, I now turn my attention to mobile development, where I’m cautiously hopeful that HTML5 will make it easier in the long run to build cross-platform mobile apps.

As I started to ramp up on Android, my first thought was, “Why on earth did I ever wait so long to try this?” There’s something magical about connecting the USB cable to my phone and seeing my own work appear there. Perhaps it’s because I was an iPhone user for a few years and felt out of touch with my phone as a Java developer. At any rate, in no particular order, here are a few notes that I hope will be helpful to Android newbies like myself. If you’re an experienced Android developer, it will no doubt take me a while to catch up with you. Please feel free to post your favorite tips and tricks in the comments as we go along.

Getting Started with Android

To get started, I installed the Android Developer Tools plugin for Eclipse and started working through the tutorials on the Android Developer site. At first, I was trying too hard. To get started, you really don’t need to worry about adb or running “android” from the command line, as you can launch the AVD manager and SDK manager right from Eclipse. The tutorials are written to run apps using the emulator, but it’s easy and faster to use your actual phone:

  1. On your phone under Settings | Applications or Settings | Security, allow “Unknown sources.”
  2. On your phone under Settings | Development, enable “USB debugging.” It’s also useful to enable “Stay awake” so you don’t have to unlock the screen frequently.
  3. Plug in your phone via USB cable and choose the “Mount as disk drive” option if prompted. You should now see it listed when you run “adb devices”.
  4. In Eclipse, click Debug as | Android Application. You will be prompted to choose a device (which should show up automatically) or launch an emulator. Edit the launch configuration for each project to change the default action.
That was easy.

Creating visual appeal

A visually appealing app is a strong indication of quality and is easier than you might think to create. Android Asset Studio is an online tool that will take any image or text, size it appropriately for various screen densities, and package it so you can just drop it into your res folder. Even easier, you can do it within Eclipse: choose File | New | Android icon set and just follow the prompts.

Capturing screen shots

When you upload your app in the Android Market, you’ll need two screen shots of your app. The ADT plugin for Eclipse has a tool that makes this easy. Open the DDMS perspective and click the camera tool to snapshot a running emulator or connected device.

There’s also a third-party utility to project your phone’s screen onto your display. This is really useful when giving Android talks for your local JUG or GTUG.

Packaging your app

When you’re ready to distribute your app, you’ll need to sign the .apk file. In Eclipse, choose File | Export | Android application and it will walk you through the process, including creating a keystore. To test your app on your phone, run “adb -d install path/to/your.apk” on the command line. The -d option selects connected devices. You can also use -e to target the emulator. You may get a warning that you need to uninstall the old version of your app first. If you do, just run “adb -d uninstall package_name,” where package_name is the root Java package associated with your app, like com.turbomanage.

Publishing to the Android Market

Go to the Android Market, sign up for an account, and upload your artifacts. Your app will be scanned for malware and should show up in an hour or two. It took me only a few days to get ramped up enough to create my first app, which I packaged and published in an afternoon. It really couldn’t be easier. When you publish, do pay attention to your application version and SDK version. Note that target SDK version is distinct from minimum SDK version, and both are important for maximum compatibility across devices.

Introducing Fibonacci Series for Android

For my first app, I took a shallow dip into my creativity pool and came up with a Fibonacci Series calculator. There are several Fibonacci apps (mostly involving stock trading) already, but I just needed a simple calculator for when I’m on a dinner date with friends and suddenly can’t remember one of the five-digit Fibonacci numbers, for example. Regular readers of this blog will recognize the related sunflower illustration thrown in for good measure. The app gave me a good opportunity to use simple TextViews, a custom view for the Canvas on which to draw the sunflower, and practice handling orientation changes (go ahead, turn it sideways and see what happens). Oh, and I incorporated a tabbed interface and the menu button also. There are lots of tutorials on these topics online already, so I think for now I’ll just point you to the source code.

As a newcomer from GWT, I found the concept of an Activity very familiar (GWT’s Activities and Places are deliberately modelled after the Android). I ran across only a few gotchas. One that I remember is that overriding onConfigurationChanged() in your Activity does not guarantee you will get notified of all orientation changes because it doesn’t get called if another app is in the foreground when the orientation changes. But no matter, you can check every time in the Activity’s onCreate() method. It also took me longer than it should have to figure out how to hook into the phone’s menu button (just override onCreateOptionsMenu()). The tutorials on the Android Developer site as well as the new Android Training section under Resources cover most of the beginner topics quite well.

For new developers, the single most useful page on the site is this one: Common Tasks.

And don’t forget the android tag on Stack Overflow, which Google officially supports.

Once again, here’s the source.

Enjoy!

Oh, and if you’re wondering about all the status bar icons in the screen shot above, yes, I really did publish the latest version to the Android Market while on the plane, listening to music, with USB cable connected. Android development is pretty addictive…

Posted in Android | 5 Comments »

 
%d bloggers like this: