Some native activity sample code cleanup.

Update to include newest headers and library, tweak glue code to
work better with state saving and add support for config changes.

Change-Id: I4d27bd4a0f542f217efaec86cf4f219aca020426
diff --git a/ndk/platforms/android-9/arch-arm/usr/include/android/asset_manager.h b/ndk/platforms/android-9/arch-arm/usr/include/android/asset_manager.h
index 89989f8..4fa0ef3 100644
--- a/ndk/platforms/android-9/arch-arm/usr/include/android/asset_manager.h
+++ b/ndk/platforms/android-9/arch-arm/usr/include/android/asset_manager.h
@@ -18,8 +18,6 @@
 #ifndef ANDROID_ASSET_MANAGER_H
 #define ANDROID_ASSET_MANAGER_H
 
-#include <jni.h>
-
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -43,14 +41,6 @@
 
 
 /**
- * Given a Dalvik AssetManager object, obtain the corresponding native AAssetManager
- * object.  Note that the caller is responsible for obtaining and holding a VM reference
- * to the jobject to prevent its being garbage collected while the native object is
- * in use.
- */
-AAssetManager* AAssetManager_fromJava(JNIEnv* env, jobject assetManager);
-
-/**
  * Open the named directory within the asset hierarchy.  The directory can then
  * be inspected with the AAssetDir functions.  To open the top-level directory,
  * pass in "" as the dirName.
diff --git a/ndk/platforms/android-9/arch-arm/usr/include/android/asset_manager_jni.h b/ndk/platforms/android-9/arch-arm/usr/include/android/asset_manager_jni.h
new file mode 100644
index 0000000..aec2d3c
--- /dev/null
+++ b/ndk/platforms/android-9/arch-arm/usr/include/android/asset_manager_jni.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+
+#ifndef ANDROID_ASSET_MANAGER_JNI_H
+#define ANDROID_ASSET_MANAGER_JNI_H
+
+#include <android/asset_manager.h>
+#include <jni.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Given a Dalvik AssetManager object, obtain the corresponding native AAssetManager
+ * object.  Note that the caller is responsible for obtaining and holding a VM reference
+ * to the jobject to prevent its being garbage collected while the native object is
+ * in use.
+ */
+AAssetManager* AAssetManager_fromJava(JNIEnv* env, jobject assetManager);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif      // ANDROID_ASSET_MANAGER_JNI_H
diff --git a/ndk/platforms/android-9/arch-arm/usr/include/android/configuration.h b/ndk/platforms/android-9/arch-arm/usr/include/android/configuration.h
new file mode 100644
index 0000000..79b9b1e
--- /dev/null
+++ b/ndk/platforms/android-9/arch-arm/usr/include/android/configuration.h
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef ANDROID_CONFIGURATION_H
+#define ANDROID_CONFIGURATION_H
+
+#include <android/asset_manager.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct AConfiguration;
+typedef struct AConfiguration AConfiguration;
+
+enum {
+    ACONFIGURATION_ORIENTATION_ANY  = 0x0000,
+    ACONFIGURATION_ORIENTATION_PORT = 0x0001,
+    ACONFIGURATION_ORIENTATION_LAND = 0x0002,
+    ACONFIGURATION_ORIENTATION_SQUARE = 0x0003,
+
+    ACONFIGURATION_TOUCHSCREEN_ANY  = 0x0000,
+    ACONFIGURATION_TOUCHSCREEN_NOTOUCH  = 0x0001,
+    ACONFIGURATION_TOUCHSCREEN_STYLUS  = 0x0002,
+    ACONFIGURATION_TOUCHSCREEN_FINGER  = 0x0003,
+
+    ACONFIGURATION_DENSITY_DEFAULT = 0,
+    ACONFIGURATION_DENSITY_LOW = 120,
+    ACONFIGURATION_DENSITY_MEDIUM = 160,
+    ACONFIGURATION_DENSITY_HIGH = 240,
+    ACONFIGURATION_DENSITY_NONE = 0xffff,
+
+    ACONFIGURATION_KEYBOARD_ANY  = 0x0000,
+    ACONFIGURATION_KEYBOARD_NOKEYS  = 0x0001,
+    ACONFIGURATION_KEYBOARD_QWERTY  = 0x0002,
+    ACONFIGURATION_KEYBOARD_12KEY  = 0x0003,
+
+    ACONFIGURATION_NAVIGATION_ANY  = 0x0000,
+    ACONFIGURATION_NAVIGATION_NONAV  = 0x0001,
+    ACONFIGURATION_NAVIGATION_DPAD  = 0x0002,
+    ACONFIGURATION_NAVIGATION_TRACKBALL  = 0x0003,
+    ACONFIGURATION_NAVIGATION_WHEEL  = 0x0004,
+
+    ACONFIGURATION_KEYSHIDDEN_ANY = 0x0000,
+    ACONFIGURATION_KEYSHIDDEN_NO = 0x0001,
+    ACONFIGURATION_KEYSHIDDEN_YES = 0x0002,
+    ACONFIGURATION_KEYSHIDDEN_SOFT = 0x0003,
+
+    ACONFIGURATION_NAVHIDDEN_ANY = 0x0000,
+    ACONFIGURATION_NAVHIDDEN_NO = 0x0001,
+    ACONFIGURATION_NAVHIDDEN_YES = 0x0002,
+
+    ACONFIGURATION_SCREENSIZE_ANY  = 0x00,
+    ACONFIGURATION_SCREENSIZE_SMALL = 0x01,
+    ACONFIGURATION_SCREENSIZE_NORMAL = 0x02,
+    ACONFIGURATION_SCREENSIZE_LARGE = 0x03,
+    ACONFIGURATION_SCREENSIZE_XLARGE = 0x04,
+
+    ACONFIGURATION_SCREENLONG_ANY = 0x00,
+    ACONFIGURATION_SCREENLONG_NO = 0x1,
+    ACONFIGURATION_SCREENLONG_YES = 0x2,
+
+    ACONFIGURATION_UI_MODE_TYPE_ANY = 0x00,
+    ACONFIGURATION_UI_MODE_TYPE_NORMAL = 0x01,
+    ACONFIGURATION_UI_MODE_TYPE_DESK = 0x02,
+    ACONFIGURATION_UI_MODE_TYPE_CAR = 0x03,
+
+    ACONFIGURATION_UI_MODE_NIGHT_ANY = 0x00,
+    ACONFIGURATION_UI_MODE_NIGHT_NO = 0x10,
+    ACONFIGURATION_UI_MODE_NIGHT_YES = 0x20,
+
+    ACONFIGURATION_MCC = 0x0001,
+    ACONFIGURATION_MNC = 0x0002,
+    ACONFIGURATION_LOCALE = 0x0004,
+    ACONFIGURATION_TOUCHSCREEN = 0x0008,
+    ACONFIGURATION_KEYBOARD = 0x0010,
+    ACONFIGURATION_KEYBOARD_HIDDEN = 0x0020,
+    ACONFIGURATION_NAVIGATION = 0x0040,
+    ACONFIGURATION_ORIENTATION = 0x0080,
+    ACONFIGURATION_DENSITY = 0x0100,
+    ACONFIGURATION_SCREEN_SIZE = 0x0200,
+    ACONFIGURATION_VERSION = 0x0400,
+    ACONFIGURATION_SCREEN_LAYOUT = 0x0800,
+    ACONFIGURATION_UI_MODE = 0x1000,
+};
+
+/**
+ * Create a new AConfiguration, initialized with no values set.
+ */
+AConfiguration* AConfiguration_new();
+
+/**
+ * Free an AConfiguration that was previously created with
+ * AConfiguration_new().
+ */
+void AConfiguration_delete(AConfiguration* config);
+
+/**
+ * Create and return a new AConfiguration based on the current configuration in
+ * use in the given AssetManager.
+ */
+void AConfiguration_fromAssetManager(AConfiguration* out, AAssetManager* am);
+
+/**
+ * Copy the contents of 'src' to 'dest'.
+ */
+void AConfiguration_copy(AConfiguration* dest, AConfiguration* src);
+
+/**
+ * Return the current MCC set in the configuration.  0 if not set.
+ */
+int32_t AConfiguration_getMcc(AConfiguration* config);
+
+/**
+ * Set the current MCC in the configuration.  0 to clear.
+ */
+void AConfiguration_setMcc(AConfiguration* config, int32_t mcc);
+
+/**
+ * Return the current MNC set in the configuration.  0 if not set.
+ */
+int32_t AConfiguration_getMnc(AConfiguration* config);
+
+/**
+ * Set the current MNC in the configuration.  0 to clear.
+ */
+void AConfiguration_setMnc(AConfiguration* config, int32_t mnc);
+
+/**
+ * Return the current language code set in the configuration.  The output will
+ * be filled with an array of two characters.  They are not 0-terminated.  If
+ * a language is not set, they will be 0.
+ */
+void AConfiguration_getLanguage(AConfiguration* config, char* outLanguage);
+
+/**
+ * Set the current language code in the configuration, from the first two
+ * characters in the string.
+ */
+void AConfiguration_setLanguage(AConfiguration* config, const char* language);
+
+/**
+ * Return the current country code set in the configuration.  The output will
+ * be filled with an array of two characters.  They are not 0-terminated.  If
+ * a country is not set, they will be 0.
+ */
+void AConfiguration_getCountry(AConfiguration* config, char* outCountry);
+
+/**
+ * Set the current country code in the configuration, from the first two
+ * characters in the string.
+ */
+void AConfiguration_setCountry(AConfiguration* config, const char* country);
+
+/**
+ * Return the current ACONFIGURATION_ORIENTATION_* set in the configuration.
+ */
+int32_t AConfiguration_getOrientation(AConfiguration* config);
+
+/**
+ * Set the current orientation in the configuration.
+ */
+void AConfiguration_setOrientation(AConfiguration* config, int32_t orientation);
+
+/**
+ * Return the current ACONFIGURATION_TOUCHSCREEN_* set in the configuration.
+ */
+int32_t AConfiguration_getTouchscreen(AConfiguration* config);
+
+/**
+ * Set the current touchscreen in the configuration.
+ */
+void AConfiguration_setTouchscreen(AConfiguration* config, int32_t touchscreen);
+
+/**
+ * Return the current ACONFIGURATION_DENSITY_* set in the configuration.
+ */
+int32_t AConfiguration_getDensity(AConfiguration* config);
+
+/**
+ * Set the current density in the configuration.
+ */
+void AConfiguration_setDensity(AConfiguration* config, int32_t density);
+
+/**
+ * Return the current ACONFIGURATION_KEYBOARD_* set in the configuration.
+ */
+int32_t AConfiguration_getKeyboard(AConfiguration* config);
+
+/**
+ * Set the current keyboard in the configuration.
+ */
+void AConfiguration_setKeyboard(AConfiguration* config, int32_t keyboard);
+
+/**
+ * Return the current ACONFIGURATION_NAVIGATION_* set in the configuration.
+ */
+int32_t AConfiguration_getNavigation(AConfiguration* config);
+
+/**
+ * Set the current navigation in the configuration.
+ */
+void AConfiguration_setNavigation(AConfiguration* config, int32_t navigation);
+
+/**
+ * Return the current ACONFIGURATION_KEYSHIDDEN_* set in the configuration.
+ */
+int32_t AConfiguration_getKeysHidden(AConfiguration* config);
+
+/**
+ * Set the current keys hidden in the configuration.
+ */
+void AConfiguration_setKeysHidden(AConfiguration* config, int32_t keysHidden);
+
+/**
+ * Return the current ACONFIGURATION_NAVHIDDEN_* set in the configuration.
+ */
+int32_t AConfiguration_getNavHidden(AConfiguration* config);
+
+/**
+ * Set the current nav hidden in the configuration.
+ */
+void AConfiguration_setNavHidden(AConfiguration* config, int32_t navHidden);
+
+/**
+ * Return the current SDK (API) version set in the configuration.
+ */
+int32_t AConfiguration_getSdkVersion(AConfiguration* config);
+
+/**
+ * Set the current SDK version in the configuration.
+ */
+void AConfiguration_setSdkVersion(AConfiguration* config, int32_t sdkVersion);
+
+/**
+ * Return the current ACONFIGURATION_SCREENSIZE_* set in the configuration.
+ */
+int32_t AConfiguration_getScreenSize(AConfiguration* config);
+
+/**
+ * Set the current screen size in the configuration.
+ */
+void AConfiguration_setScreenSize(AConfiguration* config, int32_t screenSize);
+
+/**
+ * Return the current ACONFIGURATION_SCREENLONG_* set in the configuration.
+ */
+int32_t AConfiguration_getScreenLong(AConfiguration* config);
+
+/**
+ * Set the current screen long in the configuration.
+ */
+void AConfiguration_setScreenLong(AConfiguration* config, int32_t screenLong);
+
+/**
+ * Return the current ACONFIGURATION_UI_MODE_TYPE_* set in the configuration.
+ */
+int32_t AConfiguration_getUiModeType(AConfiguration* config);
+
+/**
+ * Set the current UI mode type in the configuration.
+ */
+void AConfiguration_setUiModeType(AConfiguration* config, int32_t uiModeType);
+
+/**
+ * Return the current ACONFIGURATION_UI_MODE_NIGHT_* set in the configuration.
+ */
+int32_t AConfiguration_getUiModeNight(AConfiguration* config);
+
+/**
+ * Set the current UI mode night in the configuration.
+ */
+void AConfiguration_setUiModeNight(AConfiguration* config, int32_t uiModeNight);
+
+/**
+ * Perform a diff between two configurations.  Returns a bit mask of
+ * ACONFIGURATION_* constants, each bit set meaning that configuration element
+ * is different between them.
+ */
+int32_t AConfiguration_diff(AConfiguration* config1, AConfiguration* config2);
+
+/**
+ * Determine whether 'base' is a valid configuration for use within the
+ * environment 'requested'.  Returns 0 if there are any values in 'base'
+ * that conflict with 'requested'.  Returns 1 if it does not conflict.
+ */
+int32_t AConfiguration_match(AConfiguration* base, AConfiguration* requested);
+
+/**
+ * Determine whether the configuration in 'test' is better than the existing
+ * configuration in 'base'.  If 'requested' is non-NULL, this decision is based
+ * on the overall configuration given there.  If it is NULL, this decision is
+ * simply based on which configuration is more specific.  Returns non-0 if
+ * 'test' is better than 'base'.
+ *
+ * This assumes you have already filtered the configurations with
+ * AConfiguration_match().
+ */
+int32_t AConfiguration_isBetterThan(AConfiguration* base, AConfiguration* test,
+        AConfiguration* requested);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // ANDROID_CONFIGURATION_H
diff --git a/ndk/platforms/android-9/arch-arm/usr/include/android/input.h b/ndk/platforms/android-9/arch-arm/usr/include/android/input.h
index 0b8c7e4..243c33c 100644
--- a/ndk/platforms/android-9/arch-arm/usr/include/android/input.h
+++ b/ndk/platforms/android-9/arch-arm/usr/include/android/input.h
@@ -40,6 +40,7 @@
  * NOTE: These functions MUST be implemented by /system/lib/libui.so
  */
 
+#include <stdint.h>
 #include <sys/types.h>
 #include <android/keycodes.h>
 #include <android/looper.h>
@@ -268,7 +269,6 @@
 /*
  * Input sources.
  *
- * The appropriate interpretation for an input event depends on its source.
  * Refer to the documentation on android.view.InputDevice for more details about input sources
  * and their correct interpretation.
  */
@@ -297,6 +297,37 @@
 };
 
 /*
+ * Keyboard types.
+ *
+ * Refer to the documentation on android.view.InputDevice for more details.
+ */
+enum {
+    AINPUT_KEYBOARD_TYPE_NONE = 0,
+    AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC = 1,
+    AINPUT_KEYBOARD_TYPE_ALPHABETIC = 2,
+};
+
+/*
+ * Constants used to retrieve information about the range of motion for a particular
+ * coordinate of a motion event.
+ *
+ * Refer to the documentation on android.view.InputDevice for more details about input sources
+ * and their correct interpretation.
+ */
+enum {
+    AINPUT_MOTION_RANGE_X = 0,
+    AINPUT_MOTION_RANGE_Y = 1,
+    AINPUT_MOTION_RANGE_PRESSURE = 2,
+    AINPUT_MOTION_RANGE_SIZE = 3,
+    AINPUT_MOTION_RANGE_TOUCH_MAJOR = 4,
+    AINPUT_MOTION_RANGE_TOUCH_MINOR = 5,
+    AINPUT_MOTION_RANGE_TOOL_MAJOR = 6,
+    AINPUT_MOTION_RANGE_TOOL_MINOR = 7,
+    AINPUT_MOTION_RANGE_ORIENTATION = 8,
+};
+
+
+/*
  * Input event accessors.
  *
  * Note that most functions can only be used on input events that are of a given type.
@@ -475,7 +506,7 @@
  * upwards, is perfectly circular or is of unknown orientation.  A positive angle
  * indicates that the major axis of contact is oriented to the right.  A negative angle
  * indicates that the major axis of contact is oriented to the left.
- * The full range is from -PI/4 radians (finger pointing fully left) to PI/4 radians
+ * The full range is from -PI/2 radians (finger pointing fully left) to PI/2 radians
  * (finger pointing fully right). */
 float AMotionEvent_getOrientation(const AInputEvent* motion_event, size_t pointer_index);
 
@@ -575,7 +606,7 @@
  * upwards, is perfectly circular or is of unknown orientation.  A positive angle
  * indicates that the major axis of contact is oriented to the right.  A negative angle
  * indicates that the major axis of contact is oriented to the left.
- * The full range is from -PI/4 radians (finger pointing fully left) to PI/4 radians
+ * The full range is from -PI/2 radians (finger pointing fully left) to PI/2 radians
  * (finger pointing fully right). */
 float AMotionEvent_getHistoricalOrientation(const AInputEvent* motion_event, size_t pointer_index,
         size_t history_index);
@@ -631,6 +662,64 @@
  */
 void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled);
 
+/*
+ * Input devices.
+ *
+ * These functions provide a mechanism for querying the set of available input devices
+ * and their characteristics and capabilities.
+ */
+struct AInputDevice;
+typedef struct AInputDevice AInputDevice;
+
+/*
+ * Populates the supplied array with the ids of all input devices in the system.
+ * Sets nActual to the actual number of devices.
+ * Returns zero if enumeration was successful.
+ * Returns non-zero if the actual number of devices is greater than nMax, in which case the
+ * client should call the method again with a larger id buffer.
+ */
+int32_t AInputDevice_getDeviceIds(int32_t* idBuf, size_t nMax, size_t* nActual);
+
+/*
+ * Acquires a device by id.
+ * Returns NULL if the device was not found.
+ *
+ * Note: The returned object must be freed using AInputDevice_release when no longer needed.
+ */
+AInputDevice* AInputDevice_acquire(int32_t deviceId);
+
+/*
+ * Releases a device previously acquired by AInputDevice_acquire.
+ * If device is NULL, this function does nothing.
+ */
+void AInputDevice_release(AInputDevice* device);
+
+/*
+ * Gets the name of an input device.
+ *
+ * Note: The caller should copy the name into a private buffer since the returned pointer
+ * will become invalid when the device object is released.
+ */
+const char* AInputDevice_getName(AInputDevice* device);
+
+/*
+ * Gets the combination of input sources provided by the input device.
+ */
+uint32_t AInputDevice_getSources(AInputDevice* device);
+
+/*
+ * Gets the keyboard type.
+ */
+int32_t AInputDevice_getKeyboardType(AInputDevice* device);
+
+/* Gets the minimum value, maximum value, flat position and error tolerance for a
+ * particular motion coodinate.
+ * Returns zero if the device supports the specified motion range. */
+int32_t AInputDevice_getMotionRange(AInputDevice* device, int32_t rangeType,
+        float* outMin, float* outMax, float* outFlat, float* outFuzz);
+
+//TODO hasKey, keymap stuff, etc...
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/ndk/platforms/android-9/arch-arm/usr/include/android/native_activity.h b/ndk/platforms/android-9/arch-arm/usr/include/android/native_activity.h
index ee4204d..d74e1ce 100644
--- a/ndk/platforms/android-9/arch-arm/usr/include/android/native_activity.h
+++ b/ndk/platforms/android-9/arch-arm/usr/include/android/native_activity.h
@@ -197,6 +197,12 @@
     void (*onContentRectChanged)(ANativeActivity* activity, const ARect* rect);
 
     /**
+     * The current device AConfiguration has changed.  The new configuration can
+     * be retrieved from assetManager.
+     */
+    void (*onConfigurationChanged)(ANativeActivity* activity);
+
+    /**
      * The system is running low on memory.  Use this callback to release
      * resources you do not need, to help the system avoid killing more
      * important processes.
@@ -208,7 +214,9 @@
  * This is the function that must be in the native code to instantiate the
  * application's native activity.  It is called with the activity instance (see
  * above); if the code is being instantiated from a previously saved instance,
- * the savedState will be non-NULL and point to the saved data.
+ * the savedState will be non-NULL and point to the saved data.  You must make
+ * any copy of this data you need -- it will be released after you return from
+ * this function.
  */
 typedef void ANativeActivity_createFunc(ANativeActivity* activity,
         void* savedState, size_t savedStateSize);
diff --git a/ndk/platforms/android-9/arch-arm/usr/include/android/native_window.h b/ndk/platforms/android-9/arch-arm/usr/include/android/native_window.h
index 7599d7e..ad03d0e 100644
--- a/ndk/platforms/android-9/arch-arm/usr/include/android/native_window.h
+++ b/ndk/platforms/android-9/arch-arm/usr/include/android/native_window.h
@@ -36,12 +36,23 @@
 typedef struct ANativeWindow ANativeWindow;
 
 typedef struct ANativeWindow_Buffer {
+    // The number of pixels that are show horizontally.
     int32_t width;
+
+    // The number of pixels that are shown vertically.
     int32_t height;
+
+    // The number of *pixels* that a line in the buffer takes in
+    // memory.  This may be >= width.
     int32_t stride;
+
+    // The format of the buffer.  One of WINDOW_FORMAT_*
     int32_t format;
+
+    // The actual bits.
     void* bits;
     
+    // Do not touch.
     uint32_t reserved[6];
 } ANativeWindow_Buffer;
 
diff --git a/ndk/platforms/android-9/arch-arm/usr/include/android/sensor.h b/ndk/platforms/android-9/arch-arm/usr/include/android/sensor.h
index 4291d3e..b4ce024 100644
--- a/ndk/platforms/android-9/arch-arm/usr/include/android/sensor.h
+++ b/ndk/platforms/android-9/arch-arm/usr/include/android/sensor.h
@@ -87,6 +87,7 @@
  * A sensor event.
  */
 
+/* NOTE: Must match hardware/sensors.h */
 typedef struct ASensorVector {
     union {
         float v[3];
@@ -95,23 +96,33 @@
             float y;
             float z;
         };
+        struct {
+            float azimuth;
+            float pitch;
+            float roll;
+        };
     };
     int8_t status;
     uint8_t reserved[3];
 } ASensorVector;
 
+/* NOTE: Must match hardware/sensors.h */
 typedef struct ASensorEvent {
-    int sensor;
+    int32_t version; /* sizeof(struct ASensorEvent) */
+    int32_t sensor;
+    int32_t type;
     int32_t reserved0;
+    int64_t timestamp;
     union {
         float           data[16];
+        ASensorVector   vector;
         ASensorVector   acceleration;
         ASensorVector   magnetic;
         float           temperature;
         float           distance;
         float           light;
+        float           pressure;
     };
-    int64_t timestamp;
     int32_t reserved1[4];
 } ASensorEvent;
 
@@ -124,6 +135,8 @@
 
 struct ASensor;
 typedef struct ASensor ASensor;
+typedef ASensor const* ASensorRef;
+typedef ASensorRef const* ASensorList;
 
 /*****************************************************************************/
 
@@ -141,13 +154,13 @@
 /*
  * Returns the list of available sensors.
  */
-int ASensorManager_getSensorList(ASensorManager* manager, ASensor** list);
+int ASensorManager_getSensorList(ASensorManager* manager, ASensorList* list);
 
 /*
  * Returns the default sensor for the given type, or NULL if no sensor
  * of that type exist.
  */
-ASensor* ASensorManager_getDefaultSensor(ASensorManager* manager, int type);
+ASensor const* ASensorManager_getDefaultSensor(ASensorManager* manager, int type);
 
 /*
  * Creates a new sensor event queue and associate it with a looper.
@@ -166,20 +179,21 @@
 /*
  * Enable the selected sensor. Returns a negative error code on failure.
  */
-int ASensorEventQueue_enableSensor(ASensorEventQueue* queue, ASensor* sensor);
+int ASensorEventQueue_enableSensor(ASensorEventQueue* queue, ASensor const* sensor);
 
 /*
  * Disable the selected sensor. Returns a negative error code on failure.
  */
-int ASensorEventQueue_disableSensor(ASensorEventQueue* queue, ASensor* sensor);
+int ASensorEventQueue_disableSensor(ASensorEventQueue* queue, ASensor const* sensor);
 
 /*
  * Sets the delivery rate of events in microseconds for the given sensor.
  * Note that this is a hint only, generally event will arrive at a higher
- * rate.
+ * rate. It is an error to set a rate inferior to the value returned by
+ * ASensor_getMinDelay().
  * Returns a negative error code on failure.
  */
-int ASensorEventQueue_setEventRate(ASensorEventQueue* queue, ASensor* sensor, int32_t usec);
+int ASensorEventQueue_setEventRate(ASensorEventQueue* queue, ASensor const* sensor, int32_t usec);
 
 /*
  * Returns true if there are one or more events available in the
@@ -210,22 +224,29 @@
 /*
  * Returns this sensor's name (non localized)
  */
-const char* ASensor_getName(ASensor* sensor);
+const char* ASensor_getName(ASensor const* sensor);
 
 /*
  * Returns this sensor's vendor's name (non localized)
  */
-const char* ASensor_getVendor(ASensor* sensor);
+const char* ASensor_getVendor(ASensor const* sensor);
 
 /*
  * Return this sensor's type
  */
-int ASensor_getType(ASensor* sensor);
+int ASensor_getType(ASensor const* sensor);
 
 /*
  * Returns this sensors's resolution
  */
-float ASensor_getResolution(ASensor* sensor);
+float ASensor_getResolution(ASensor const* sensor);
+
+/*
+ * Returns the minimum delay allowed between events in microseconds.
+ * A value of zero means that this sensor doesn't report events at a
+ * constant rate, but rather only when a new data is available.
+ */
+int ASensor_getMinDelay(ASensor const* sensor);
 
 
 #ifdef __cplusplus
diff --git a/ndk/platforms/android-9/arch-arm/usr/lib/libandroid.so b/ndk/platforms/android-9/arch-arm/usr/lib/libandroid.so
index 04a1e58..1b41c67 100644
--- a/ndk/platforms/android-9/arch-arm/usr/lib/libandroid.so
+++ b/ndk/platforms/android-9/arch-arm/usr/lib/libandroid.so
Binary files differ
diff --git a/ndk/platforms/android-9/samples/native-activity/AndroidManifest.xml b/ndk/platforms/android-9/samples/native-activity/AndroidManifest.xml
index e0e6bf0..1fd3620 100644
--- a/ndk/platforms/android-9/samples/native-activity/AndroidManifest.xml
+++ b/ndk/platforms/android-9/samples/native-activity/AndroidManifest.xml
@@ -1,13 +1,22 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!-- BEGIN_INCLUDE(manifest) -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-      package="com.example.native_activity"
-      android:versionCode="1"
-      android:versionName="1.0">
+        package="com.example.native_activity"
+        android:versionCode="1"
+        android:versionName="1.0">
+
+    <!-- This is the platform API where NativeActivity was introduced. -->
     <uses-sdk android:minSdkVersion="8" />
-    <application android:label="@string/app_name"
-                 android:hasCode="false" android:debuggable="true">
+
+    <!-- This .apk has no Java code itself, so set hasCode to false. -->
+    <application android:label="@string/app_name" android:hasCode="false">
+
+        <!-- Our activity is the built-in NativeActivity framework class.
+             This will take care of integrating with our NDK code. -->
         <activity android:name="android.app.NativeActivity"
-                  android:label="@string/app_name">
+                android:label="@string/app_name"
+                android:configChanges="orientation|keyboardHidden">
+            <!-- Tell NativeActivity the name of or .so -->
             <meta-data android:name="android.app.lib_name"
                     android:value="native-activity" />
             <intent-filter>
@@ -16,4 +25,6 @@
             </intent-filter>
         </activity>
     </application>
+
 </manifest> 
+<!-- END_INCLUDE(manifest) -->
diff --git a/ndk/platforms/android-9/samples/native-activity/jni/main.c b/ndk/platforms/android-9/samples/native-activity/jni/main.c
index 4807fd9..9d83f04 100644
--- a/ndk/platforms/android-9/samples/native-activity/jni/main.c
+++ b/ndk/platforms/android-9/samples/native-activity/jni/main.c
@@ -15,6 +15,7 @@
  *
  */
 
+//BEGIN_INCLUDE(all)
 #include <jni.h>
 
 #include <errno.h>
@@ -23,6 +24,18 @@
 
 #include "glutils.h"
 
+/**
+ * Our saved state data.
+ */
+struct saved_state {
+    float angle;
+    int32_t x;
+    int32_t y;
+};
+
+/**
+ * Shared state for our app.
+ */
 struct engine {
     struct android_app* app;
 
@@ -32,11 +45,12 @@
     EGLContext context;
     int32_t width;
     int32_t height;
-    float angle;
-    int32_t x;
-    int32_t y;
+    struct saved_state state;
 };
 
+/**
+ * Initialize an EGL context for the current display.
+ */
 static int engine_init_display(struct engine* engine) {
     // initialize opengl and egl
     const EGLint attribs[] = {
@@ -68,7 +82,7 @@
     engine->surface = surface;
     engine->width = w;
     engine->height = h;
-    engine->angle = 0;
+    engine->state.angle = 0;
 
     // Initialize GL state.
     glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
@@ -79,39 +93,26 @@
     return 0;
 }
 
+/**
+ * Just the current frame in the display.
+ */
 static void engine_draw_frame(struct engine* engine) {
     if (engine->display == NULL) {
         // No display.
         return;
     }
 
-    glClearColor(((float)engine->x)/engine->width, engine->angle,
-            ((float)engine->y)/engine->height, 1);
+    // Just fill the screen with a color.
+    glClearColor(((float)engine->state.x)/engine->width, engine->state.angle,
+            ((float)engine->state.y)/engine->height, 1);
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
-#if 0
-    glMatrixMode(GL_MODELVIEW);
-    glLoadIdentity();
-    glTranslatef(0, 0, -3.0f);
-    glRotatef(engine->angle,        0, 1, 0);
-    glRotatef(engine->angle*0.25f,  1, 0, 0);
-
-    glEnableClientState(GL_VERTEX_ARRAY);
-    glEnableClientState(GL_COLOR_ARRAY);
-
-    //mCube.draw(gl);
-
-    glRotatef(engine->angle*2.0f, 0, 1, 1);
-    glTranslatef(0.5f, 0.5f, 0.5f);
-
-    //mCube.draw(gl);
-#endif
-
     eglSwapBuffers(engine->display, engine->surface);
-
-    //engine->angle += 1.2f;
 }
 
+/**
+ * Tear down the EGL context currently associated with the display.
+ */
 static int engine_term_display(struct engine* engine) {
     if (engine->display != EGL_NO_DISPLAY) {
         eglMakeCurrent(engine->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
@@ -129,89 +130,106 @@
     engine->surface = EGL_NO_SURFACE;
 }
 
-static int engine_do_ui_event(struct engine* engine) {
-    AInputEvent* event = NULL;
-    if (AInputQueue_getEvent(engine->app->inputQueue, &event) >= 0) {
-        LOGI("New input event: type=%d\n", AInputEvent_getType(event));
-        if (AInputQueue_preDispatchEvent(engine->app->inputQueue, event)) {
-            return 1;
-        }
-        if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
-            engine->animating = 1;
-            engine->x = AMotionEvent_getX(event, 0);
-            engine->y = AMotionEvent_getY(event, 0);
-            AInputQueue_finishEvent(engine->app->inputQueue, event, 1);
-        } else {
-            AInputQueue_finishEvent(engine->app->inputQueue, event, 0);
-        }
-    } else {
-        LOGI("Failure reading next input event: %s\n", strerror(errno));
+/**
+ * Process the next input event.
+ */
+static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) {
+    struct engine* engine = (struct engine*)app->userData;
+    if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
+        engine->animating = 1;
+        engine->state.x = AMotionEvent_getX(event, 0);
+        engine->state.y = AMotionEvent_getY(event, 0);
+        return 1;
     }
-
-    return 1;
+    return 0;
 }
 
-static int32_t engine_do_main_cmd(struct engine* engine) {
-    int32_t res;
-    int8_t cmd = android_app_read_cmd(engine->app);
+/**
+ * Process the next main command.
+ */
+static void engine_handle_cmd(struct android_app* app, int32_t cmd) {
+    struct engine* engine = (struct engine*)app->userData;
     switch (cmd) {
-        case APP_CMD_WINDOW_CHANGED:
-            engine_term_display(engine);
-            res = android_app_exec_cmd(engine->app, cmd);
+        case APP_CMD_SAVE_STATE:
+            engine->app->savedState = malloc(sizeof(struct saved_state));
+            *((struct saved_state*)engine->app->savedState) = engine->state;
+            engine->app->savedStateSize = sizeof(struct saved_state);
+            break;
+        case APP_CMD_INIT_WINDOW:
             if (engine->app->window != NULL) {
                 engine_init_display(engine);
                 engine_draw_frame(engine);
             }
             break;
+        case APP_CMD_TERM_WINDOW:
+            engine_term_display(engine);
+            break;
         case APP_CMD_LOST_FOCUS:
-            res = android_app_exec_cmd(engine->app, cmd);
             engine->animating = 0;
             engine_draw_frame(engine);
             break;
-        default:
-            res = android_app_exec_cmd(engine->app, cmd);
-            break;
     }
-
-    return res;
 }
 
+/**
+ * This is the main entry point of a native application that is using
+ * android_native_app_glue.  It runs in its own thread, with its own
+ * event loop for receiving input events and doing other things.
+ */
 void android_main(struct android_app* state) {
     struct engine engine;
 
+    // Make sure glue isn't stripped.
+    app_dummy();
+
     memset(&engine, 0, sizeof(engine));
     state->userData = &engine;
+    state->onAppCmd = engine_handle_cmd;
+    state->onInputEvent = engine_handle_input;
     engine.app = state;
 
+    if (state->savedState != NULL) {
+        // We are starting with a previous saved state; restore from it.
+        engine.state = *(struct saved_state*)state->savedState;
+    }
+
     // loop waiting for stuff to do.
 
     while (1) {
         // Read all pending events.
         int fd;
         int events;
-        void* data;
-        while ((fd=ALooper_pollAll(engine.animating ? 0 : -1, &events, &data)) >= 0) {
-            switch ((int)data) {
-                case LOOPER_ID_MAIN:
-                    if (!engine_do_main_cmd(&engine)) {
-                        LOGI("Engine thread destroy requested!");
-                        engine_term_display(&engine);
-                        return;
-                    }
-                    break;
-                case LOOPER_ID_EVENT:
-                    engine_do_ui_event(&engine);
-                    break;
+        struct android_poll_source* source;
+
+        // If not animating, we will block forever waiting for events.
+        // If animating, we loop until all events are read, then continue
+        // to draw the next frame of animation.
+        while ((fd=ALooper_pollAll(engine.animating ? 0 : -1, &events,
+                (void**)&source)) >= 0) {
+
+            // Process this event.
+            if (source != NULL) {
+                source->process(state);
+            }
+
+            // Check if we are exiting.
+            if (state->destroyRequested != 0) {
+                engine_term_display(&engine);
+                return;
             }
         }
 
         if (engine.animating) {
             // Done with events; draw next animation frame.
-            engine.angle += .01f;
-            if (engine.angle > 1) {
-                engine.angle = 0;
+            engine.state.angle += .01f;
+            if (engine.state.angle > 1) {
+                engine.state.angle = 0;
             }
+
+            // Drawing is throttled to the screen update rate, so there
+            // is no need to do timing here.
             engine_draw_frame(&engine);
         }
     }
 }
+//END_INCLUDE(all)
diff --git a/ndk/platforms/android-9/samples/native-activity/src/Dummy.java b/ndk/platforms/android-9/samples/native-activity/src/Dummy.java
new file mode 100644
index 0000000..596215a
--- /dev/null
+++ b/ndk/platforms/android-9/samples/native-activity/src/Dummy.java
@@ -0,0 +1,4 @@
+// Temporary until the NDK build system can deal with there being no Java source.
+class Dummy {
+
+}
diff --git a/ndk/platforms/android-9/samples/native-plasma/jni/plasma.c b/ndk/platforms/android-9/samples/native-plasma/jni/plasma.c
index 6cf8b8e..6d725ae 100644
--- a/ndk/platforms/android-9/samples/native-plasma/jni/plasma.c
+++ b/ndk/platforms/android-9/samples/native-plasma/jni/plasma.c
@@ -411,53 +411,37 @@
     engine->animating = 0;
 }
 
-static int engine_do_ui_event(struct engine* engine) {
-    AInputEvent* event = NULL;
-    if (AInputQueue_getEvent(engine->app->inputQueue, &event) >= 0) {
-        if (AInputQueue_preDispatchEvent(engine->app->inputQueue, event)) {
-            return 1;
-        }
-        if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
-            engine->animating = 1;
-            AInputQueue_finishEvent(engine->app->inputQueue, event, 1);
-        } else if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY) {
-            LOGI("Key event: action=%d keyCode=%d metaState=0x%x",
-                    AKeyEvent_getAction(event),
-                    AKeyEvent_getKeyCode(event),
-                    AKeyEvent_getMetaState(event));
-            AInputQueue_finishEvent(engine->app->inputQueue, event, 0);
-        } else {
-            AInputQueue_finishEvent(engine->app->inputQueue, event, 0);
-        }
-    } else {
-        LOGI("Failure reading next input event: %s\n", strerror(errno));
+static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) {
+    struct engine* engine = (struct engine*)app->userData;
+    if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
+        engine->animating = 1;
+        return 1;
+    } else if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY) {
+        LOGI("Key event: action=%d keyCode=%d metaState=0x%x",
+                AKeyEvent_getAction(event),
+                AKeyEvent_getKeyCode(event),
+                AKeyEvent_getMetaState(event));
     }
 
-    return 1;
+    return 0;
 }
 
-static int32_t engine_do_main_cmd(struct engine* engine) {
-    int32_t res;
-    int8_t cmd = android_app_read_cmd(engine->app);
+static void engine_handle_cmd(struct android_app* app, int32_t cmd) {
+    struct engine* engine = (struct engine*)app->userData;
     switch (cmd) {
-        case APP_CMD_WINDOW_CHANGED:
-            engine_term_display(engine);
-            res = android_app_exec_cmd(engine->app, cmd);
+        case APP_CMD_INIT_WINDOW:
             if (engine->app->window != NULL) {
                 engine_draw_frame(engine);
             }
             break;
+        case APP_CMD_TERM_WINDOW:
+            engine_term_display(engine);
+            break;
         case APP_CMD_LOST_FOCUS:
-            res = android_app_exec_cmd(engine->app, cmd);
             engine->animating = 0;
             engine_draw_frame(engine);
             break;
-        default:
-            res = android_app_exec_cmd(engine->app, cmd);
-            break;
     }
-
-    return res;
 }
 
 void android_main(struct android_app* state) {
@@ -465,8 +449,13 @@
 
     struct engine engine;
 
+    // Make sure glue isn't stripped.
+    app_dummy();
+
     memset(&engine, 0, sizeof(engine));
     state->userData = &engine;
+    state->onAppCmd = engine_handle_cmd;
+    state->onInputEvent = engine_handle_input;
     engine.app = state;
 
     if (!init) {
@@ -482,19 +471,24 @@
         // Read all pending events.
         int fd;
         int events;
-        void* data;
-        while ((fd=ALooper_pollAll(engine.animating ? 0 : -1, &events, &data)) >= 0) {
-            switch ((int)data) {
-                case LOOPER_ID_MAIN:
-                    if (!engine_do_main_cmd(&engine)) {
-                        LOGI("Engine thread destroy requested!");
-                        engine_term_display(&engine);
-                        return;
-                    }
-                    break;
-                case LOOPER_ID_EVENT:
-                    engine_do_ui_event(&engine);
-                    break;
+        struct android_poll_source* source;
+
+        // If not animating, we will block forever waiting for events.
+        // If animating, we loop until all events are read, then continue
+        // to draw the next frame of animation.
+        while ((fd=ALooper_pollAll(engine.animating ? 0 : -1, &events,
+                (void**)&source)) >= 0) {
+
+            // Process this event.
+            if (source != NULL) {
+                source->process(state);
+            }
+
+            // Check if we are exiting.
+            if (state->destroyRequested != 0) {
+                LOGI("Engine thread destroy requested!");
+                engine_term_display(&engine);
+                return;
             }
         }
 
diff --git a/ndk/platforms/android-9/samples/native-plasma/src/Dummy.java b/ndk/platforms/android-9/samples/native-plasma/src/Dummy.java
index 4160c66..596215a 100644
--- a/ndk/platforms/android-9/samples/native-plasma/src/Dummy.java
+++ b/ndk/platforms/android-9/samples/native-plasma/src/Dummy.java
@@ -1,4 +1,4 @@
+// Temporary until the NDK build system can deal with there being no Java source.
+class Dummy {
 
-// Only needed for the build system.
-public class Dummy {
 }
diff --git a/ndk/sources/android/native_app_glue/android_native_app_glue.c b/ndk/sources/android/native_app_glue/android_native_app_glue.c
index d7a8391..05c638ed 100644
--- a/ndk/sources/android/native_app_glue/android_native_app_glue.c
+++ b/ndk/sources/android/native_app_glue/android_native_app_glue.c
@@ -26,19 +26,58 @@
 #include <android/log.h>
 
 #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "threaded_app", __VA_ARGS__))
-#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "threaded_app", __VA_ARGS__))
+
+static void free_saved_state(struct android_app* android_app) {
+    pthread_mutex_lock(&android_app->mutex);
+    if (android_app->savedState != NULL) {
+        free(android_app->savedState);
+        android_app->savedState = NULL;
+        android_app->savedStateSize = 0;
+    }
+    pthread_mutex_unlock(&android_app->mutex);
+}
 
 int8_t android_app_read_cmd(struct android_app* android_app) {
     int8_t cmd;
     if (read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd)) {
+        switch (cmd) {
+            case APP_CMD_SAVE_STATE:
+                free_saved_state(android_app);
+                break;
+        }
         return cmd;
     } else {
-        LOGW("No data on command pipe!");
+        LOGI("No data on command pipe!");
     }
     return -1;
 }
 
-int32_t android_app_exec_cmd(struct android_app* android_app, int8_t cmd) {
+static void print_cur_config(struct android_app* android_app) {
+    char lang[2], country[2];
+    AConfiguration_getLanguage(android_app->config, lang);
+    AConfiguration_getCountry(android_app->config, country);
+
+    LOGI("Config: mcc=%d mnc=%d lang=%c%c cnt=%c%c orien=%d touch=%d dens=%d "
+            "keys=%d nav=%d keysHid=%d navHid=%d sdk=%d size=%d long=%d "
+            "modetype=%d modenight=%d",
+            AConfiguration_getMcc(android_app->config),
+            AConfiguration_getMnc(android_app->config),
+            lang[0], lang[1], country[0], country[1],
+            AConfiguration_getOrientation(android_app->config),
+            AConfiguration_getTouchscreen(android_app->config),
+            AConfiguration_getDensity(android_app->config),
+            AConfiguration_getKeyboard(android_app->config),
+            AConfiguration_getNavigation(android_app->config),
+            AConfiguration_getKeysHidden(android_app->config),
+            AConfiguration_getNavHidden(android_app->config),
+            AConfiguration_getSdkVersion(android_app->config),
+            AConfiguration_getScreenSize(android_app->config),
+            AConfiguration_getScreenLong(android_app->config),
+            AConfiguration_getUiModeType(android_app->config),
+            AConfiguration_getUiModeNight(android_app->config));
+}
+
+void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd) {
     switch (cmd) {
         case APP_CMD_INPUT_CHANGED:
             LOGI("APP_CMD_INPUT_CHANGED\n");
@@ -50,22 +89,30 @@
             if (android_app->inputQueue != NULL) {
                 LOGI("Attaching input queue to looper");
                 AInputQueue_attachLooper(android_app->inputQueue,
-                        android_app->looper, NULL, (void*)LOOPER_ID_EVENT);
+                        android_app->looper, NULL, &android_app->inputPollSource);
             }
             pthread_cond_broadcast(&android_app->cond);
             pthread_mutex_unlock(&android_app->mutex);
             break;
 
-        case APP_CMD_WINDOW_CHANGED:
-            LOGI("APP_CMD_WINDOW_CHANGED\n");
+        case APP_CMD_INIT_WINDOW:
+            LOGI("APP_CMD_INIT_WINDOW\n");
             pthread_mutex_lock(&android_app->mutex);
             android_app->window = android_app->pendingWindow;
             pthread_cond_broadcast(&android_app->cond);
             pthread_mutex_unlock(&android_app->mutex);
             break;
 
-        case APP_CMD_START:
+        case APP_CMD_TERM_WINDOW:
+            LOGI("APP_CMD_TERM_WINDOW\n");
+            pthread_mutex_lock(&android_app->mutex);
+            android_app->window = NULL;
+            pthread_cond_broadcast(&android_app->cond);
+            pthread_mutex_unlock(&android_app->mutex);
+            break;
+
         case APP_CMD_RESUME:
+        case APP_CMD_START:
         case APP_CMD_PAUSE:
         case APP_CMD_STOP:
             LOGI("activityState=%d\n", cmd);
@@ -75,32 +122,101 @@
             pthread_mutex_unlock(&android_app->mutex);
             break;
 
+        case APP_CMD_CONFIG_CHANGED:
+            LOGI("APP_CMD_CONFIG_CHANGED\n");
+            AConfiguration_fromAssetManager(android_app->config,
+                    android_app->activity->assetManager);
+            print_cur_config(android_app);
+            break;
+
         case APP_CMD_DESTROY:
             LOGI("APP_CMD_DESTROY\n");
             android_app->destroyRequested = 1;
             break;
     }
+}
 
-    return android_app->destroyRequested ? 0 : 1;
+void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd) {
+    switch (cmd) {
+        case APP_CMD_TERM_WINDOW:
+            LOGI("APP_CMD_TERM_WINDOW\n");
+            pthread_mutex_lock(&android_app->mutex);
+            android_app->window = NULL;
+            pthread_cond_broadcast(&android_app->cond);
+            pthread_mutex_unlock(&android_app->mutex);
+            break;
+
+        case APP_CMD_SAVE_STATE:
+            LOGI("APP_CMD_SAVE_STATE\n");
+            pthread_mutex_lock(&android_app->mutex);
+            android_app->stateSaved = 1;
+            pthread_cond_broadcast(&android_app->cond);
+            pthread_mutex_unlock(&android_app->mutex);
+            break;
+
+        case APP_CMD_RESUME:
+            free_saved_state(android_app);
+            break;
+    }
+}
+
+void app_dummy() {
+
 }
 
 static void android_app_destroy(struct android_app* android_app) {
     LOGI("android_app_destroy!");
+    free_saved_state(android_app);
     pthread_mutex_lock(&android_app->mutex);
     if (android_app->inputQueue != NULL) {
         AInputQueue_detachLooper(android_app->inputQueue);
     }
+    AConfiguration_delete(android_app->config);
     android_app->destroyed = 1;
     pthread_cond_broadcast(&android_app->cond);
     pthread_mutex_unlock(&android_app->mutex);
     // Can't touch android_app object after this.
 }
 
+static void process_input(struct android_app* app) {
+    AInputEvent* event = NULL;
+    if (AInputQueue_getEvent(app->inputQueue, &event) >= 0) {
+        LOGI("New input event: type=%d\n", AInputEvent_getType(event));
+        if (AInputQueue_preDispatchEvent(app->inputQueue, event)) {
+            return;
+        }
+        int32_t handled = 0;
+        if (app->onInputEvent != NULL) handled = app->onInputEvent(app, event);
+        AInputQueue_finishEvent(app->inputQueue, event, handled);
+    } else {
+        LOGI("Failure reading next input event: %s\n", strerror(errno));
+    }
+}
+
+static void process_cmd(struct android_app* app) {
+    int8_t cmd = android_app_read_cmd(app);
+    android_app_pre_exec_cmd(app, cmd);
+    if (app->onAppCmd != NULL) app->onAppCmd(app, cmd);
+    android_app_post_exec_cmd(app, cmd);
+}
+
 static void* android_app_entry(void* param) {
     struct android_app* android_app = (struct android_app*)param;
 
+    android_app->config = AConfiguration_new();
+    AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager);
+
+    print_cur_config(android_app);
+
+    android_app->cmdPollSource.id = LOOPER_ID_MAIN;
+    android_app->cmdPollSource.app = android_app;
+    android_app->cmdPollSource.process = process_cmd;
+    android_app->inputPollSource.id = LOOPER_ID_INPUT;
+    android_app->inputPollSource.app = android_app;
+    android_app->inputPollSource.process = process_input;
+
     ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
-    ALooper_addFd(looper, android_app->msgread, POLLIN, NULL, (void*)LOOPER_ID_MAIN);
+    ALooper_addFd(looper, android_app->msgread, POLLIN, NULL, &android_app->cmdPollSource);
     android_app->looper = looper;
 
     pthread_mutex_lock(&android_app->mutex);
@@ -118,7 +234,8 @@
 // Native activity interaction (called from main thread)
 // --------------------------------------------------------------------
 
-static struct android_app* android_app_create(ANativeActivity* activity) {
+static struct android_app* android_app_create(ANativeActivity* activity,
+        void* savedState, size_t savedStateSize) {
     struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app));
     memset(android_app, 0, sizeof(struct android_app));
     android_app->activity = activity;
@@ -126,6 +243,12 @@
     pthread_mutex_init(&android_app->mutex, NULL);
     pthread_cond_init(&android_app->cond, NULL);
 
+    if (savedState != NULL) {
+        android_app->savedState = malloc(savedStateSize);
+        android_app->savedStateSize = savedStateSize;
+        memcpy(android_app->savedState, savedState, savedStateSize);
+    }
+
     int msgpipe[2];
     if (pipe(msgpipe)) {
         LOGI("could not create pipe: %s", strerror(errno));
@@ -166,8 +289,13 @@
 
 static void android_app_set_window(struct android_app* android_app, ANativeWindow* window) {
     pthread_mutex_lock(&android_app->mutex);
+    if (android_app->pendingWindow != NULL) {
+        android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW);
+    }
     android_app->pendingWindow = window;
-    android_app_write_cmd(android_app, APP_CMD_WINDOW_CHANGED);
+    if (window != NULL) {
+        android_app_write_cmd(android_app, APP_CMD_INIT_WINDOW);
+    }
     while (android_app->window != android_app->pendingWindow) {
         pthread_cond_wait(&android_app->cond, &android_app->mutex);
     }
@@ -214,8 +342,27 @@
 }
 
 static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen) {
+    struct android_app* android_app = (struct android_app*)activity->instance;
+    void* savedState = NULL;
+
     LOGI("SaveInstanceState: %p\n", activity);
-    return NULL;
+    pthread_mutex_lock(&android_app->mutex);
+    android_app->stateSaved = 0;
+    android_app_write_cmd(android_app, APP_CMD_SAVE_STATE);
+    while (!android_app->stateSaved) {
+        pthread_cond_wait(&android_app->cond, &android_app->mutex);
+    }
+
+    if (android_app->savedState != NULL) {
+        savedState = android_app->savedState;
+        *outLen = android_app->savedStateSize;
+        android_app->savedState = NULL;
+        android_app->savedStateSize = 0;
+    }
+
+    pthread_mutex_unlock(&android_app->mutex);
+
+    return savedState;
 }
 
 static void onPause(ANativeActivity* activity) {
@@ -228,8 +375,16 @@
     android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_STOP);
 }
 
+static void onConfigurationChanged(ANativeActivity* activity) {
+    struct android_app* android_app = (struct android_app*)activity->instance;
+    LOGI("ConfigurationChanged: %p\n", activity);
+    android_app_write_cmd(android_app, APP_CMD_CONFIG_CHANGED);
+}
+
 static void onLowMemory(ANativeActivity* activity) {
+    struct android_app* android_app = (struct android_app*)activity->instance;
     LOGI("LowMemory: %p\n", activity);
+    android_app_write_cmd(android_app, APP_CMD_LOW_MEMORY);
 }
 
 static void onWindowFocusChanged(ANativeActivity* activity, int focused) {
@@ -267,6 +422,7 @@
     activity->callbacks->onSaveInstanceState = onSaveInstanceState;
     activity->callbacks->onPause = onPause;
     activity->callbacks->onStop = onStop;
+    activity->callbacks->onConfigurationChanged = onConfigurationChanged;
     activity->callbacks->onLowMemory = onLowMemory;
     activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
     activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
@@ -274,5 +430,5 @@
     activity->callbacks->onInputQueueCreated = onInputQueueCreated;
     activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
 
-    activity->instance = android_app_create(activity);
+    activity->instance = android_app_create(activity, savedState, savedStateSize);
 }
diff --git a/ndk/sources/android/native_app_glue/android_native_app_glue.h b/ndk/sources/android/native_app_glue/android_native_app_glue.h
index e30e960..e60f1c0 100644
--- a/ndk/sources/android/native_app_glue/android_native_app_glue.h
+++ b/ndk/sources/android/native_app_glue/android_native_app_glue.h
@@ -22,8 +22,9 @@
 #include <pthread.h>
 #include <sched.h>
 
-#include <android/native_activity.h>
+#include <android/configuration.h>
 #include <android/looper.h>
+#include <android/native_activity.h>
 
 #ifdef __cplusplus
 extern "C"
@@ -59,7 +60,7 @@
  *      - input events coming from the AInputQueue attached to the activity.
  *
  *    Each of these correspond to an ALooper callback that returns a "data"
- *    value of LOOPER_ID_MAIN and LOOPER_ID_EVENT, respectively.
+ *    value of LOOPER_ID_MAIN and LOOPER_ID_INPUT, respectively.
  *
  *    Your application can use the same ALooper to listen to additionnal
  *    file-descriptors.
@@ -71,7 +72,7 @@
  *
  *    XXX: MAKE THIS STUFF MORE CLEAR !!
  *
- * 5/ Whenever you receive a LOOPER_ID_EVENT event from the ALooper, you
+ * 5/ Whenever you receive a LOOPER_ID_INPUT event from the ALooper, you
  *    should read one event from the AInputQueue with AInputQueue_getEvent().
  *
  * See the sample named "native-activity" that comes with the NDK with a
@@ -79,6 +80,25 @@
  *
  */
 
+struct android_app;
+
+/**
+ * Data associated with an ALooper fd that will be returned as the "outData"
+ * when that source has data ready.
+ */
+struct android_poll_source {
+    // The identifier of this source.  May be LOOPER_ID_MAIN or
+    // LOOPER_ID_INPUT.
+    int32_t id;
+
+    // The android_app this fd is associated with.
+    struct android_app* app;
+
+    // Function to call to perform the standard processing of data from
+    // this source.
+    void (*process)(struct android_app* app);
+};
+
 /**
  * This is the interface for the standard glue code of a threaded
  * application.  In this model, the application's code is running
@@ -92,9 +112,32 @@
     // here if it likes.
     void* userData;
 
+    // Fill this in with the function to process main app commands (APP_CMD_*)
+    void (*onAppCmd)(struct android_app* app, int32_t cmd);
+
+    // Fill this in with the function to process input events.  At this point
+    // the event has already been pre-dispatched, and it will be finished upon
+    // return.  Return 1 if you have handled the event, 0 for any default
+    // dispatching.
+    int32_t (*onInputEvent)(struct android_app* app, AInputEvent* event);
+
     // The ANativeActivity object instance that this app is running in.
     ANativeActivity* activity;
 
+    // The current configuration the app is running in.
+    AConfiguration* config;
+
+    // This is the last instance's saved state, as provided at creation time.
+    // It is NULL if there was no state.  You can use this as you need; the
+    // memory will remain around until you call android_app_exec_cmd() for
+    // APP_CMD_RESUME, at which point it will be freed and savedState set to NULL.
+    // These variables should only be changed when processing a APP_CMD_SAVE_STATE,
+    // at which point they will be initialized to NULL and you can malloc your
+    // state and place the information here.  In that case the memory will be
+    // freed for you later.
+    void* savedState;
+    size_t savedStateSize;
+
     // The ALooper associated with the app's thread.
     ALooper* looper;
 
@@ -113,6 +156,10 @@
     // APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below.
     int activityState;
 
+    // This is non-zero when the application's NativeActivity is being
+    // destroyed and waiting for the app thread to complete.
+    int destroyRequested;
+
     // -------------------------------------------------
     // Below are "private" implementation of the glue code.
 
@@ -124,11 +171,11 @@
 
     pthread_t thread;
 
-    // This is non-zero when the application's NativeActivity is being
-    // destroyed and waiting for the app thread to complete.
-    int destroyRequested;
+    struct android_poll_source cmdPollSource;
+    struct android_poll_source inputPollSource;
 
     int running;
+    int stateSaved;
     int destroyed;
     int redrawNeeded;
     AInputQueue* pendingInputQueue;
@@ -149,7 +196,7 @@
      * application's window.  These can be read via the inputQueue
      * object of android_app.
      */
-    LOOPER_ID_EVENT = 2
+    LOOPER_ID_INPUT = 2
 };
 
 enum {
@@ -161,11 +208,19 @@
     APP_CMD_INPUT_CHANGED,
 
     /**
-     * Command from main thread: the ANativeWindow has changed.  Upon processing
-     * this command, android_app->window will be updated to the new window surface
-     * (or NULL).
+     * Command from main thread: a new ANativeWindow is ready for use.  Upon
+     * receiving this command, android_app->window will contain the new window
+     * surface.
      */
-    APP_CMD_WINDOW_CHANGED,
+    APP_CMD_INIT_WINDOW,
+
+    /**
+     * Command from main thread: the existing ANativeWindow needs to be
+     * terminated.  Upon receiving this command, android_app->window still
+     * contains the existing window; after calling android_app_exec_cmd
+     * it will be set to NULL.
+     */
+    APP_CMD_TERM_WINDOW,
 
     /**
      * Command from main thread: the current ANativeWindow has been resized.
@@ -200,6 +255,11 @@
     APP_CMD_LOST_FOCUS,
 
     /**
+     * Command from main thread: the current device configuration has changed.
+     */
+    APP_CMD_CONFIG_CHANGED,
+
+    /**
      * Command from main thread: the system is running low on memory.
      * Try to reduce your memory use.
      */
@@ -216,6 +276,15 @@
     APP_CMD_RESUME,
 
     /**
+     * Command from main thread: the app should generate a new saved state
+     * for itself, to restore from later if needed.  If you have saved state,
+     * allocate it with malloc and place it in android_app.savedState with
+     * the size in android_app.savedStateSize.  The will be freed for you
+     * later.
+     */
+    APP_CMD_SAVE_STATE,
+
+    /**
      * Command from main thread: the app's activity has been paused.
      */
     APP_CMD_PAUSE,
@@ -240,12 +309,22 @@
 
 /**
  * Call with the command returned by android_app_read_cmd() to do the
- * default processing of the given command.
- *
- * Important: returns 0 if the app should exit.  You must ALWAYS check for
- * a zero return and, if found, exit your android_main() function.
+ * initial pre-processing of the given command.  You can perform your own
+ * actions for the command after calling this function.
  */
-int32_t android_app_exec_cmd(struct android_app* android_app, int8_t cmd);
+void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd);
+
+/**
+ * Call with the command returned by android_app_read_cmd() to do the
+ * final post-processing of the given command.  You must have done your own
+ * actions for the command before calling this function.
+ */
+void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd);
+
+/**
+ * Dummy function you can call to ensure glue code isn't stripped.
+ */
+void app_dummy();
 
 /**
  * This is the function that application code must implement, representing