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,773 hits

Posts Tagged ‘android’

Enable multi-user support in the Android emulator

Posted by David Chandler on February 20, 2013

Android 4.2 (API 17) offers multi-user support for tablet sharing. To add a user on a physical tablet running 4.2 or later, go to Settings | Users. You can also do this in an emulator, but you first have to set an emulator property as follows:

  1. Create a new AVD based on a tablet (say, the Nexus 7 device definition in the latest ADT) with API 17.
  2. Start the emulator
  3. Run these adb commands:

> adb shell setprop fw.max_users 4
> adb shell stop
> adb shell start

You can now add a user in the emulator. To see the new user bubble on the lock screen, press F7. You may have to press it twice for the slide lock to become active.
Advertisements

Posted in Android | Tagged: | 1 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 »

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 »

 
%d bloggers like this: