Merge "EmulatedFakeCamera2: Use HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED" into jb-mr1-dev
diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetworkVars.java b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetworkVars.java
index ff3a686..9abfe26 100644
--- a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetworkVars.java
+++ b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetworkVars.java
@@ -15,7 +15,7 @@
  */
 package com.android.commands.monkey;
 
-import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerGlobal;
 import android.os.Build;
 import android.os.SystemClock;
 import android.view.Display;
@@ -82,7 +82,7 @@
         VAR_MAP.put("build.version.codename", new StaticVarGetter(Build.VERSION.CODENAME));
 
         // Display
-        Display display = DisplayManager.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY);
+        Display display = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY);
         VAR_MAP.put("display.width", new StaticVarGetter(Integer.toString(display.getWidth())));
         VAR_MAP.put("display.height", new StaticVarGetter(Integer.toString(display.getHeight())));
 
diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java
index e0ebd03..a7f538d 100644
--- a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java
+++ b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java
@@ -18,7 +18,7 @@
 
 import android.content.ComponentName;
 import android.graphics.PointF;
-import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerGlobal;
 import android.os.SystemClock;
 import android.view.Display;
 import android.view.KeyCharacterMap;
@@ -259,7 +259,7 @@
      *
      */
     private void generatePointerEvent(Random random, int gesture) {
-        Display display = DisplayManager.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY);
+        Display display = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY);
 
         PointF p1 = randomPoint(random, display);
         PointF v1 = randomVector(random);
diff --git a/host/windows/usb/android_winusb.inf b/host/windows/usb/android_winusb.inf
index b4462cd..f26a75c 100755
--- a/host/windows/usb/android_winusb.inf
+++ b/host/windows/usb/android_winusb.inf
@@ -6,15 +6,10 @@
 Class               = AndroidUsbDeviceClass

 ClassGuid           = {3F966BD9-FA04-4ec5-991C-D326973B5128}

 Provider            = %ProviderName%

-DriverVer           = 05/24/2012,6.0.0000.00000

+DriverVer           = 08/27/2012,7.0.0000.00001

 CatalogFile.NTx86   = androidwinusb86.cat

 CatalogFile.NTamd64 = androidwinusba64.cat

 

-;

-; This section seems to be required for WinUsb driver installation.

-; If this section is removed the installer will report an error

-; "Required section not found in INF file".

-;

 [ClassInstall32]

 Addreg = AndroidWinUsbClassReg

 

@@ -22,9 +17,11 @@
 HKR,,,0,%ClassName%

 HKR,,Icon,,-1

 

+

 [Manufacturer]

 %ProviderName% = Google, NTx86, NTamd64

 

+

 [Google.NTx86]

 

 ;Google Nexus One

@@ -46,6 +43,21 @@
 %CompositeAdbInterface%     = USB_Install, USB\VID_18D1&PID_4E42&MI_01

 %CompositeAdbInterface%     = USB_Install, USB\VID_18D1&PID_4E44&MI_01

 

+;Google Nexus Q

+%SingleBootLoaderInterface% = USB_Install, USB\VID_18D1&PID_2C10

+%SingleAdbInterface%        = USB_Install, USB\VID_18D1&PID_2C11

+

+;Google Nexus (generic)

+%SingleBootLoaderInterface% = USB_Install, USB\VID_18D1&PID_4EE0

+%SingleAdbInterface%        = USB_Install, USB\VID_18D1&PID_4EE1

+%CompositeAdbInterface%     = USB_Install, USB\VID_18D1&PID_4EE2

+%CompositeAdbInterface%     = USB_Install, USB\VID_18D1&PID_4EE2&MI_01

+%SingleAdbInterface%        = USB_Install, USB\VID_18D1&PID_4EE3

+%CompositeAdbInterface%     = USB_Install, USB\VID_18D1&PID_4EE4&MI_01

+%SingleAdbInterface%        = USB_Install, USB\VID_18D1&PID_4EE5

+%CompositeAdbInterface%     = USB_Install, USB\VID_18D1&PID_4EE6&MI_01

+

+

 [Google.NTamd64]

 

 ;Google Nexus One

@@ -67,6 +79,20 @@
 %CompositeAdbInterface%     = USB_Install, USB\VID_18D1&PID_4E42&MI_01

 %CompositeAdbInterface%     = USB_Install, USB\VID_18D1&PID_4E44&MI_01

 

+;Google Nexus Q

+%SingleBootLoaderInterface% = USB_Install, USB\VID_18D1&PID_2C10

+%SingleAdbInterface%        = USB_Install, USB\VID_18D1&PID_2C11

+

+;Google Nexus (generic)

+%SingleBootLoaderInterface% = USB_Install, USB\VID_18D1&PID_4EE0

+%SingleAdbInterface%        = USB_Install, USB\VID_18D1&PID_4EE1

+%CompositeAdbInterface%     = USB_Install, USB\VID_18D1&PID_4EE2

+%CompositeAdbInterface%     = USB_Install, USB\VID_18D1&PID_4EE2&MI_01

+%SingleAdbInterface%        = USB_Install, USB\VID_18D1&PID_4EE3

+%CompositeAdbInterface%     = USB_Install, USB\VID_18D1&PID_4EE4&MI_01

+%SingleAdbInterface%        = USB_Install, USB\VID_18D1&PID_4EE5

+%CompositeAdbInterface%     = USB_Install, USB\VID_18D1&PID_4EE6&MI_01

+

 [USB_Install]

 Include = winusb.inf

 Needs   = WINUSB.NT

@@ -127,4 +153,4 @@
 SingleBootLoaderInterface   = "Android Bootloader Interface"

 WinUSB_SvcDesc              = "Android USB Driver"

 DISK_NAME                   = "Android WinUsb installation disk"

-ClassName                   = "Android Phone"

+ClassName                   = "Android Device"

diff --git a/host/windows/usb/readme.txt b/host/windows/usb/readme.txt
index 961b45a..d01bc98 100755
--- a/host/windows/usb/readme.txt
+++ b/host/windows/usb/readme.txt
@@ -15,7 +15,7 @@
     * WdfCoInstaller01007.dll

     * WinUSBCoInstaller.dll

     * WUDFUpdate_01007.dll

-    

+

 File contained in i386 and amd64 subfolders are Microsoft distributives needed

 to install WinUsb framework. These files can be obtained from WDK 'redist'

 folder, respectively to the OS: copy x86 files to i386 subfolder, and amd64

diff --git a/ide/eclipse/.classpath b/ide/eclipse/.classpath
index 0626e5f..bb34b54 100644
--- a/ide/eclipse/.classpath
+++ b/ide/eclipse/.classpath
@@ -11,9 +11,11 @@
 	<classpathentry kind="src" path="packages/apps/DeskClock/src"/>
 	<classpathentry kind="src" path="packages/apps/Email/src"/>
 	<classpathentry kind="src" path="packages/apps/Email/emailcommon/src"/>
+	<classpathentry kind="src" path="packages/apps/Email/emailsync/src"/>
 	<classpathentry kind="src" path="packages/apps/Gallery2/src"/>
 	<classpathentry kind="src" path="packages/apps/Gallery2/src_pd"/>
 	<classpathentry kind="src" path="packages/apps/Gallery2/gallerycommon/src"/>
+	<classpathentry kind="src" path="packages/apps/Gallery2/actionbarsherlock/src"/>
 	<classpathentry kind="src" path="packages/apps/HTMLViewer/src"/>
 	<classpathentry kind="src" path="packages/apps/Launcher2/src"/>
 	<classpathentry kind="src" path="packages/apps/Mms/src"/>
diff --git a/ndk/platforms/android-5/samples/hello-gl2/default.properties b/ndk/platforms/android-5/samples/hello-gl2/default.properties
index dbf05f2..9d135cb 100644
--- a/ndk/platforms/android-5/samples/hello-gl2/default.properties
+++ b/ndk/platforms/android-5/samples/hello-gl2/default.properties
@@ -8,4 +8,4 @@
 # project structure.
 
 # Project target.
-target=android-5
+target=android-7
diff --git a/ndk/platforms/android-9/arch-mips/src/crtbegin_so.S b/ndk/platforms/android-9/arch-mips/src/crtbegin_so.S
index f4fc9b8..68dddfe 100644
--- a/ndk/platforms/android-9/arch-mips/src/crtbegin_so.S
+++ b/ndk/platforms/android-9/arch-mips/src/crtbegin_so.S
@@ -38,24 +38,7 @@
 	.long -1
 	.long __do_global_dtors_aux
 
-	.section .ctors, "aw"
-	.type __CTOR_LIST__, @object
-	.globl __CTOR_LIST__
-__CTOR_LIST__:
-	.long -1
-
-	.section .dtors, "aw"
-	.type __DTOR_LIST__, @object
-	.globl __DTOR_LIST__
-__DTOR_LIST__:
-	.long -1
-
 	.abicalls
-	.section	.eh_frame,"a",@progbits
-	.align	2
-	.type	__EH_FRAME_BEGIN__, @object
-	.size	__EH_FRAME_BEGIN__, 0
-__EH_FRAME_BEGIN__:
 	.text
 	.align	2
 	.set	nomips16
@@ -105,8 +88,6 @@
 	.size	__do_global_dtors_aux, .-__do_global_dtors_aux
 	.local	completed.1269
 	.comm	completed.1269,1,1
-	.local	object.1265
-	.comm	object.1265,24,4
 	.weak	__cxa_finalize
 
 .include "__dso_handle.S"
diff --git a/ndk/platforms/android-9/arch-mips/src/crtend_so.S b/ndk/platforms/android-9/arch-mips/src/crtend_so.S
index d0bb090..f09c427 100644
--- a/ndk/platforms/android-9/arch-mips/src/crtend_so.S
+++ b/ndk/platforms/android-9/arch-mips/src/crtend_so.S
@@ -3,21 +3,3 @@
 
 	.section .fini_array, "aw"
 	.long 0
-
-	.section .ctors, "aw", @progbits
-	.type __CTOR_END__, @object
-__CTOR_END__:
-	.long 0
-	
-	.section .dtors, "aw", @progbits
-	.type __DTOR_END__, @object
-__DTOR_END__:
-	.long 0
-
-	.section	.eh_frame,"a",@progbits
-	.align 4
-	.type	__FRAME_END__, @object
-	.size	__FRAME_END__, 4
-__FRAME_END__:
-	.zero	4
-	
diff --git a/ndk/platforms/android-9/samples/native-activity/default.properties b/ndk/platforms/android-9/samples/native-activity/default.properties
index 9a2c9f6..8010039 100644
--- a/ndk/platforms/android-9/samples/native-activity/default.properties
+++ b/ndk/platforms/android-9/samples/native-activity/default.properties
@@ -8,4 +8,4 @@
 # project structure.
 
 # Project target.
-target=android-9
+target=android-10
diff --git a/ndk/platforms/android-9/samples/native-activity/jni/Application.mk b/ndk/platforms/android-9/samples/native-activity/jni/Application.mk
index 22d188e..682f11b 100644
--- a/ndk/platforms/android-9/samples/native-activity/jni/Application.mk
+++ b/ndk/platforms/android-9/samples/native-activity/jni/Application.mk
@@ -1 +1 @@
-APP_PLATFORM := android-9
+APP_PLATFORM := android-10
diff --git a/ndk/platforms/android-9/samples/native-audio/default.properties b/ndk/platforms/android-9/samples/native-audio/default.properties
index eada70a..d63a41e 100644
--- a/ndk/platforms/android-9/samples/native-audio/default.properties
+++ b/ndk/platforms/android-9/samples/native-audio/default.properties
@@ -8,6 +8,6 @@
 # project structure.
 
 # Project target.
-target=android-9
+target=android-10
 # Indicates whether an apk should be generated for each density.
 split.density=false
diff --git a/ndk/platforms/android-9/samples/native-plasma/default.properties b/ndk/platforms/android-9/samples/native-plasma/default.properties
index 9a2c9f6..8010039 100644
--- a/ndk/platforms/android-9/samples/native-plasma/default.properties
+++ b/ndk/platforms/android-9/samples/native-plasma/default.properties
@@ -8,4 +8,4 @@
 # project structure.
 
 # Project target.
-target=android-9
+target=android-10
diff --git a/ndk/platforms/android-9/samples/native-plasma/jni/Application.mk b/ndk/platforms/android-9/samples/native-plasma/jni/Application.mk
index 23fa139..70bbb62 100644
--- a/ndk/platforms/android-9/samples/native-plasma/jni/Application.mk
+++ b/ndk/platforms/android-9/samples/native-plasma/jni/Application.mk
@@ -1,3 +1,3 @@
 # The ARMv7 is significanly faster due to the use of the hardware FPU
 APP_ABI := armeabi armeabi-v7a
-APP_PLATFORM := android-9
+APP_PLATFORM := android-10
diff --git a/sdk/usbdriver_source.properties b/sdk/usbdriver_source.properties
index 73ddf74..bff71f9 100755
--- a/sdk/usbdriver_source.properties
+++ b/sdk/usbdriver_source.properties
@@ -1,4 +1,4 @@
-Pkg.Revision=6

+Pkg.Revision=7

 Archive.Os=WINDOWS

 Archive.Arch=ANY

 Extra.Path=usb_driver

diff --git a/tools/recovery_l10n/Android.mk b/tools/recovery_l10n/Android.mk
new file mode 100644
index 0000000..937abd1
--- /dev/null
+++ b/tools/recovery_l10n/Android.mk
@@ -0,0 +1,12 @@
+# Copyright 2012 Google Inc. All Rights Reserved.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := RecoveryLocalizer
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+include $(BUILD_PACKAGE)
diff --git a/tools/recovery_l10n/AndroidManifest.xml b/tools/recovery_l10n/AndroidManifest.xml
new file mode 100644
index 0000000..8c51a4e
--- /dev/null
+++ b/tools/recovery_l10n/AndroidManifest.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.recovery_l10n">
+
+  <application android:label="Recovery Localizer">
+    <activity android:name="Main"
+              android:label="Recovery Localizer">
+      <intent-filter>
+        <action android:name="android.intent.action.MAIN" />
+        <category android:name="android.intent.category.LAUNCHER" />
+      </intent-filter>
+    </activity>
+  </application>
+
+</manifest>
+
+
diff --git a/tools/recovery_l10n/res/layout/main.xml b/tools/recovery_l10n/res/layout/main.xml
new file mode 100644
index 0000000..1ac2b24
--- /dev/null
+++ b/tools/recovery_l10n/res/layout/main.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="fill_parent"
+              android:layout_height="wrap_content"
+              >
+
+  <Spinner android:id="@+id/which"
+           android:layout_width="wrap_content"
+           android:layout_height="wrap_content"
+           />
+
+  <Button android:id="@+id/go"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:text="@string/go"
+          />
+
+  <TextView android:id="@+id/text"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textColor="#ffffffff"
+            android:background="#ff000000"
+            android:maxWidth="480px"
+            />
+
+
+</LinearLayout>
+
+
diff --git a/tools/recovery_l10n/res/values-de/strings.xml b/tools/recovery_l10n/res/values-de/strings.xml
new file mode 100644
index 0000000..a03803d
--- /dev/null
+++ b/tools/recovery_l10n/res/values-de/strings.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+  <string name="recovery_installing">Systemupdate wird installiert\u2026</string>
+  <string name="recovery_erasing">Löschen\u2026</string>
+  <string name="recovery_no_command">Kein Befehl.</string>
+  <string name="recovery_error">Fehler!</string>
+
+</resources>
diff --git a/tools/recovery_l10n/res/values/strings.xml b/tools/recovery_l10n/res/values/strings.xml
new file mode 100644
index 0000000..3a8aeec
--- /dev/null
+++ b/tools/recovery_l10n/res/values/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+  <!-- Do not translate. -->
+  <string translatable="false" name="go">Go</string>
+
+  <!-- Do not translate. -->
+  <string-array translatable="false" name="string_options">
+    <item>installing</item>
+    <item>erasing</item>
+    <item>no_command</item>
+    <item>error</item>
+  </string-array>
+
+  <!-- Displayed on the screen beneath the animated android while the
+       system is installing an update. [CHAR LIMIT=60] -->
+  <string name="recovery_installing">Installing system update\u2026</string>
+
+  <!-- Displayed on the screen beneath the animated android while the
+       system is erasing a partition (either a data wipe aka "factory
+       reset", or a cache wipe). [CHAR LIMIT=60] -->
+  <string name="recovery_erasing">Erasing\u2026</string>
+
+  <!-- Displayed on the screen when the user has gotten into recovery
+       mode without a command to run.  Will not normally happen, but
+       users (especially developers) may boot into recovery mode
+       manually via special key combinations.  [CHAR LIMIT=60] -->
+  <string name="recovery_no_command">No command.</string>
+
+  <!-- Displayed on the triangle-! screen when a system update
+       installation or data wipe procedure encounters an error.  [CHAR
+       LIMIT=60] -->
+  <string name="recovery_error">Error!</string>
+
+</resources>
diff --git a/tools/recovery_l10n/src/com/android/recovery_l10n/Main.java b/tools/recovery_l10n/src/com/android/recovery_l10n/Main.java
new file mode 100644
index 0000000..63ae3ea
--- /dev/null
+++ b/tools/recovery_l10n/src/com/android/recovery_l10n/Main.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.recovery_l10n;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.AssetManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.Spinner;
+import android.widget.ArrayAdapter;
+import android.widget.AdapterView;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Locale;
+import java.util.HashMap;
+
+/**
+ * This activity assists in generating the specially-formatted bitmaps
+ * of text needed for recovery's localized text display.  Each image
+ * contains all the translations of a single string; above each
+ * translation is a "header row" that encodes that subimage's width,
+ * height, and locale using pixel values.
+ *
+ * To use this app to generate new translations:
+ *
+ *   - Update the string resources in res/values-*
+ *
+ *   - Update the list of desired locales (mLocales) below.  Locales
+ *     should be ordered by decreasing popularity (ie, the most
+ *     commonly-used one first).
+ *
+ *   - Build and run the app.  Select the string you want to
+ *     translate, and press the "Go" button.
+ *
+ *   - Wait for it to finish cycling through all the strings, then
+ *     pull /data/data/com.android.recovery_l10n/files/text-out.png
+ *     from the device.
+ *
+ *   - "pngcrush -c 0 text-out.png output.png"
+ *
+ *   - Put output.png in bootable/recovery/res/images/ (renamed
+ *     appropriately).
+ *
+ * Recovery expects 8-bit 1-channel images (white text on black
+ * background).  pngcrush -c 0 will convert the output of this program
+ * to such an image.  If you use any other image handling tools,
+ * remember that they must be lossless to preserve the exact values of
+ * pixels in the header rows; don't convert them to jpeg or anything.
+ */
+
+public class Main extends Activity {
+    private static final String TAG = "RecoveryL10N";
+
+    final Locale[] mLocales = new Locale[] { Locale.US, Locale.GERMANY };
+
+    HashMap<Locale, Bitmap> savedBitmaps;
+    TextView mText;
+    int mStringId = R.string.recovery_installing;
+
+    public class TextCapture implements Runnable {
+        private Locale nextLocale;
+        private Locale thisLocale;
+        private Runnable next;
+
+        TextCapture(Locale thisLocale, Locale nextLocale, Runnable next) {
+            this.nextLocale = nextLocale;
+            this.thisLocale = thisLocale;
+            this.next = next;
+        }
+
+        public void run() {
+            Bitmap b = mText.getDrawingCache();
+            savedBitmaps.put(thisLocale, b.copy(Bitmap.Config.ARGB_8888, false));
+
+            if (nextLocale != null) {
+                switchTo(nextLocale);
+            }
+
+            if (next != null) {
+                mText.postDelayed(next, 200);
+            }
+        }
+    }
+
+    private void switchTo(Locale locale) {
+        Resources standardResources = getResources();
+        AssetManager assets = standardResources.getAssets();
+        DisplayMetrics metrics = standardResources.getDisplayMetrics();
+        Configuration config = new Configuration(standardResources.getConfiguration());
+        config.locale = locale;
+        Resources defaultResources = new Resources(assets, metrics, config);
+
+        mText.setText(mStringId);
+
+        mText.setDrawingCacheEnabled(false);
+        mText.setDrawingCacheEnabled(true);
+        mText.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstance) {
+        super.onCreate(savedInstance);
+        setContentView(R.layout.main);
+
+        savedBitmaps = new HashMap<Locale, Bitmap>();
+
+        Spinner spinner = (Spinner) findViewById(R.id.which);
+        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
+            this, R.array.string_options, android.R.layout.simple_spinner_item);
+        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        spinner.setAdapter(adapter);
+        spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+            @Override
+            public void onItemSelected(AdapterView parent, View view,
+                                       int pos, long id) {
+                switch (pos) {
+                    case 0: mStringId = R.string.recovery_installing; break;
+                    case 1: mStringId = R.string.recovery_erasing; break;
+                    case 2: mStringId = R.string.recovery_no_command; break;
+                    case 3: mStringId = R.string.recovery_error; break;
+                }
+            }
+            @Override public void onNothingSelected(AdapterView parent) { }
+            });
+
+        mText = (TextView) findViewById(R.id.text);
+
+        final Runnable seq = buildSequence(mLocales);
+
+        Button b = (Button) findViewById(R.id.go);
+        b.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View ignore) {
+                mText.post(seq);
+            }
+            });
+    }
+
+    private Runnable buildSequence(final Locale[] locales) {
+        Runnable head = new Runnable() { public void run() { mergeBitmaps(locales); } };
+        Locale prev = null;
+        for (Locale loc : locales) {
+            head = new TextCapture(loc, prev, head);
+            prev = loc;
+        }
+        final Runnable fhead = head;
+        final Locale floc = prev;
+        return new Runnable() { public void run() { startSequence(fhead, floc); } };
+    }
+
+    private void startSequence(Runnable firstRun, Locale firstLocale) {
+        savedBitmaps.clear();
+        switchTo(firstLocale);
+        mText.postDelayed(firstRun, 200);
+    }
+
+    private void saveBitmap(Bitmap b, String filename) {
+        try {
+            FileOutputStream fos = openFileOutput(filename, 0);
+            b.compress(Bitmap.CompressFormat.PNG, 100, fos);
+            fos.close();
+        } catch (IOException e) {
+            Log.i(TAG, "failed to write PNG", e);
+        }
+    }
+
+    private int colorFor(byte b) {
+        return 0xff000000 | (b<<16) | (b<<8) | b;
+    }
+
+    private int colorFor(int b) {
+        return 0xff000000 | (b<<16) | (b<<8) | b;
+    }
+
+    private void mergeBitmaps(final Locale[] locales) {
+        HashMap<String, Integer> countByLanguage = new HashMap<String, Integer>();
+
+        int height = 2;
+        int width = 10;
+        int maxHeight = 0;
+        for (Locale loc : locales) {
+            Bitmap b = savedBitmaps.get(loc);
+            int h = b.getHeight();
+            int w = b.getWidth();
+            height += h+1;
+            if (h > maxHeight) maxHeight = h;
+            if (w > width) width = w;
+
+            String lang = loc.getLanguage();
+            if (countByLanguage.containsKey(lang)) {
+                countByLanguage.put(lang, countByLanguage.get(lang)+1);
+            } else {
+                countByLanguage.put(lang, 1);
+            }
+        }
+
+        Log.i(TAG, "output bitmap is " + width + " x " + height);
+        Bitmap out = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+        out.eraseColor(0xff000000);
+        int[] pixels = new int[maxHeight * width];
+
+        int p = 0;
+        for (Locale loc : locales) {
+            Bitmap bm = savedBitmaps.get(loc);
+            int h = bm.getHeight();
+            int w = bm.getWidth();
+
+            String lang = loc.getLanguage();
+            if (countByLanguage.get(lang) > 1) {
+                lang = loc.toString();
+            }
+            Log.i(TAG, "encoding \"" + loc + "\" as \"" + lang + "\"");
+            byte[] langBytes = lang.getBytes();
+            out.setPixel(0, p, colorFor(w & 0xff));
+            out.setPixel(1, p, colorFor(w >>> 8));
+            out.setPixel(2, p, colorFor(h & 0xff));
+            out.setPixel(3, p, colorFor(h >>> 8));
+            out.setPixel(4, p, colorFor(langBytes.length));
+            int x = 5;
+            for (byte b : langBytes) {
+                out.setPixel(x, p, colorFor(b));
+                x++;
+            }
+            out.setPixel(x, p, colorFor(0));
+
+            p++;
+
+            bm.getPixels(pixels, 0, w, 0, 0, w, h);
+            out.setPixels(pixels, 0, w, 0, p, w, h);
+            p += h;
+        }
+
+        // if no languages match, suppress text display by using a
+        // single black pixel as the image.
+        out.setPixel(0, p, colorFor(1));
+        out.setPixel(1, p, colorFor(0));
+        out.setPixel(2, p, colorFor(1));
+        out.setPixel(3, p, colorFor(0));
+        out.setPixel(4, p, colorFor(0));
+        p++;
+
+        saveBitmap(out, "text-out.png");
+    }
+}