Merge "Incremental repairs to side by side stacks."
diff --git a/api/current.txt b/api/current.txt
index 110f0ea..fcfeea9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -15879,7 +15879,7 @@
     field public static final int GL_STENCIL_CLEAR_VALUE = 2961; // 0xb91
     field public static final int GL_STENCIL_FAIL = 2964; // 0xb94
     field public static final int GL_STENCIL_FUNC = 2962; // 0xb92
-    field public static final int GL_STENCIL_INDEX = 6401; // 0x1901
+    field public static final deprecated int GL_STENCIL_INDEX = 6401; // 0x1901
     field public static final int GL_STENCIL_INDEX8 = 36168; // 0x8d48
     field public static final int GL_STENCIL_PASS_DEPTH_FAIL = 2965; // 0xb95
     field public static final int GL_STENCIL_PASS_DEPTH_PASS = 2966; // 0xb96
@@ -15962,6 +15962,476 @@
     field public static final int GL_ZERO = 0; // 0x0
   }
 
+  public class GLES30 extends android.opengl.GLES20 {
+    ctor public GLES30();
+    method public static void glBeginQuery(int, int);
+    method public static void glBeginTransformFeedback(int);
+    method public static void glBindBufferBase(int, int, int);
+    method public static void glBindBufferRange(int, int, int, int, int);
+    method public static void glBindSampler(int, int);
+    method public static void glBindTransformFeedback(int, int);
+    method public static void glBindVertexArray(int);
+    method public static void glBlitFramebuffer(int, int, int, int, int, int, int, int, int, int);
+    method public static void glClearBufferfi(int, int, float, int);
+    method public static void glClearBufferfv(int, int, float[], int);
+    method public static void glClearBufferfv(int, int, java.nio.FloatBuffer);
+    method public static void glClearBufferiv(int, int, int[], int);
+    method public static void glClearBufferiv(int, int, java.nio.IntBuffer);
+    method public static void glClearBufferuiv(int, int, int[], int);
+    method public static void glClearBufferuiv(int, int, java.nio.IntBuffer);
+    method public static int glClientWaitSync(long, int, long);
+    method public static void glCompressedTexImage3D(int, int, int, int, int, int, int, int, java.nio.Buffer);
+    method public static void glCompressedTexImage3D(int, int, int, int, int, int, int, int, int);
+    method public static void glCompressedTexSubImage3D(int, int, int, int, int, int, int, int, int, int, java.nio.Buffer);
+    method public static void glCompressedTexSubImage3D(int, int, int, int, int, int, int, int, int, int, int);
+    method public static void glCopyBufferSubData(int, int, int, int, int);
+    method public static void glCopyTexSubImage3D(int, int, int, int, int, int, int, int, int);
+    method public static void glDeleteQueries(int, int[], int);
+    method public static void glDeleteQueries(int, java.nio.IntBuffer);
+    method public static void glDeleteSamplers(int, int[], int);
+    method public static void glDeleteSamplers(int, java.nio.IntBuffer);
+    method public static void glDeleteSync(long);
+    method public static void glDeleteTransformFeedbacks(int, int[], int);
+    method public static void glDeleteTransformFeedbacks(int, java.nio.IntBuffer);
+    method public static void glDeleteVertexArrays(int, int[], int);
+    method public static void glDeleteVertexArrays(int, java.nio.IntBuffer);
+    method public static void glDrawArraysInstanced(int, int, int, int);
+    method public static void glDrawBuffers(int, int[], int);
+    method public static void glDrawBuffers(int, java.nio.IntBuffer);
+    method public static void glDrawElementsInstanced(int, int, int, java.nio.Buffer, int);
+    method public static void glDrawElementsInstanced(int, int, int, int, int);
+    method public static void glDrawRangeElements(int, int, int, int, int, java.nio.Buffer);
+    method public static void glDrawRangeElements(int, int, int, int, int, int);
+    method public static void glEndQuery(int);
+    method public static void glEndTransformFeedback();
+    method public static long glFenceSync(int, int);
+    method public static void glFlushMappedBufferRange(int, int, int);
+    method public static void glFramebufferTextureLayer(int, int, int, int, int);
+    method public static void glGenQueries(int, int[], int);
+    method public static void glGenQueries(int, java.nio.IntBuffer);
+    method public static void glGenSamplers(int, int[], int);
+    method public static void glGenSamplers(int, java.nio.IntBuffer);
+    method public static void glGenTransformFeedbacks(int, int[], int);
+    method public static void glGenTransformFeedbacks(int, java.nio.IntBuffer);
+    method public static void glGenVertexArrays(int, int[], int);
+    method public static void glGenVertexArrays(int, java.nio.IntBuffer);
+    method public static void glGetActiveUniformBlockName(int, int, int, int[], int, byte[], int);
+    method public static void glGetActiveUniformBlockName(int, int, java.nio.Buffer, java.nio.Buffer);
+    method public static java.lang.String glGetActiveUniformBlockName(int, int);
+    method public static void glGetActiveUniformBlockiv(int, int, int, int[], int);
+    method public static void glGetActiveUniformBlockiv(int, int, int, java.nio.IntBuffer);
+    method public static void glGetActiveUniformsiv(int, int, int[], int, int, int[], int);
+    method public static void glGetActiveUniformsiv(int, int, java.nio.IntBuffer, int, java.nio.IntBuffer);
+    method public static void glGetBufferParameteri64v(int, int, long[], int);
+    method public static void glGetBufferParameteri64v(int, int, java.nio.LongBuffer);
+    method public static java.nio.Buffer glGetBufferPointerv(int, int);
+    method public static int glGetFragDataLocation(int, java.lang.String);
+    method public static void glGetInteger64i_v(int, int, long[], int);
+    method public static void glGetInteger64i_v(int, int, java.nio.LongBuffer);
+    method public static void glGetInteger64v(int, long[], int);
+    method public static void glGetInteger64v(int, java.nio.LongBuffer);
+    method public static void glGetIntegeri_v(int, int, int[], int);
+    method public static void glGetIntegeri_v(int, int, java.nio.IntBuffer);
+    method public static void glGetInternalformativ(int, int, int, int, int[], int);
+    method public static void glGetInternalformativ(int, int, int, int, java.nio.IntBuffer);
+    method public static void glGetProgramBinary(int, int, int[], int, int[], int, java.nio.Buffer);
+    method public static void glGetProgramBinary(int, int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.Buffer);
+    method public static void glGetQueryObjectuiv(int, int, int[], int);
+    method public static void glGetQueryObjectuiv(int, int, java.nio.IntBuffer);
+    method public static void glGetQueryiv(int, int, int[], int);
+    method public static void glGetQueryiv(int, int, java.nio.IntBuffer);
+    method public static void glGetSamplerParameterfv(int, int, float[], int);
+    method public static void glGetSamplerParameterfv(int, int, java.nio.FloatBuffer);
+    method public static void glGetSamplerParameteriv(int, int, int[], int);
+    method public static void glGetSamplerParameteriv(int, int, java.nio.IntBuffer);
+    method public static java.lang.String glGetStringi(int, int);
+    method public static void glGetSynciv(long, int, int, int[], int, int[], int);
+    method public static void glGetSynciv(long, int, int, java.nio.IntBuffer, java.nio.IntBuffer);
+    method public static void glGetTransformFeedbackVarying(int, int, int, int[], int, int[], int, int[], int, byte[], int);
+    method public static void glGetTransformFeedbackVarying(int, int, int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, byte);
+    method public static java.lang.String glGetTransformFeedbackVarying(int, int, int[], int, int[], int);
+    method public static java.lang.String glGetTransformFeedbackVarying(int, int, java.nio.IntBuffer, java.nio.IntBuffer);
+    method public static int glGetUniformBlockIndex(int, java.lang.String);
+    method public static void glGetUniformIndices(int, java.lang.String[], int[], int);
+    method public static void glGetUniformIndices(int, java.lang.String[], java.nio.IntBuffer);
+    method public static void glGetUniformuiv(int, int, int[], int);
+    method public static void glGetUniformuiv(int, int, java.nio.IntBuffer);
+    method public static void glGetVertexAttribIiv(int, int, int[], int);
+    method public static void glGetVertexAttribIiv(int, int, java.nio.IntBuffer);
+    method public static void glGetVertexAttribIuiv(int, int, int[], int);
+    method public static void glGetVertexAttribIuiv(int, int, java.nio.IntBuffer);
+    method public static void glInvalidateFramebuffer(int, int, int[], int);
+    method public static void glInvalidateFramebuffer(int, int, java.nio.IntBuffer);
+    method public static void glInvalidateSubFramebuffer(int, int, int[], int, int, int, int, int);
+    method public static void glInvalidateSubFramebuffer(int, int, java.nio.IntBuffer, int, int, int, int);
+    method public static boolean glIsQuery(int);
+    method public static boolean glIsSampler(int);
+    method public static boolean glIsSync(long);
+    method public static boolean glIsTransformFeedback(int);
+    method public static boolean glIsVertexArray(int);
+    method public static java.nio.Buffer glMapBufferRange(int, int, int, int);
+    method public static void glPauseTransformFeedback();
+    method public static void glProgramBinary(int, int, java.nio.Buffer, int);
+    method public static void glProgramParameteri(int, int, int);
+    method public static void glReadBuffer(int);
+    method public static void glRenderbufferStorageMultisample(int, int, int, int, int);
+    method public static void glResumeTransformFeedback();
+    method public static void glSamplerParameterf(int, int, float);
+    method public static void glSamplerParameterfv(int, int, float[], int);
+    method public static void glSamplerParameterfv(int, int, java.nio.FloatBuffer);
+    method public static void glSamplerParameteri(int, int, int);
+    method public static void glSamplerParameteriv(int, int, int[], int);
+    method public static void glSamplerParameteriv(int, int, java.nio.IntBuffer);
+    method public static void glTexImage3D(int, int, int, int, int, int, int, int, int, java.nio.Buffer);
+    method public static void glTexImage3D(int, int, int, int, int, int, int, int, int, int);
+    method public static void glTexStorage2D(int, int, int, int, int);
+    method public static void glTexStorage3D(int, int, int, int, int, int);
+    method public static void glTexSubImage3D(int, int, int, int, int, int, int, int, int, int, java.nio.Buffer);
+    method public static void glTexSubImage3D(int, int, int, int, int, int, int, int, int, int, int);
+    method public static void glTransformFeedbackVaryings(int, java.lang.String[], int);
+    method public static void glUniform1ui(int, int);
+    method public static void glUniform1uiv(int, int, int[], int);
+    method public static void glUniform1uiv(int, int, java.nio.IntBuffer);
+    method public static void glUniform2ui(int, int, int);
+    method public static void glUniform2uiv(int, int, int[], int);
+    method public static void glUniform2uiv(int, int, java.nio.IntBuffer);
+    method public static void glUniform3ui(int, int, int, int);
+    method public static void glUniform3uiv(int, int, int[], int);
+    method public static void glUniform3uiv(int, int, java.nio.IntBuffer);
+    method public static void glUniform4ui(int, int, int, int, int);
+    method public static void glUniform4uiv(int, int, int[], int);
+    method public static void glUniform4uiv(int, int, java.nio.IntBuffer);
+    method public static void glUniformBlockBinding(int, int, int);
+    method public static void glUniformMatrix2x3fv(int, int, boolean, float[], int);
+    method public static void glUniformMatrix2x3fv(int, int, boolean, java.nio.FloatBuffer);
+    method public static void glUniformMatrix2x4fv(int, int, boolean, float[], int);
+    method public static void glUniformMatrix2x4fv(int, int, boolean, java.nio.FloatBuffer);
+    method public static void glUniformMatrix3x2fv(int, int, boolean, float[], int);
+    method public static void glUniformMatrix3x2fv(int, int, boolean, java.nio.FloatBuffer);
+    method public static void glUniformMatrix3x4fv(int, int, boolean, float[], int);
+    method public static void glUniformMatrix3x4fv(int, int, boolean, java.nio.FloatBuffer);
+    method public static void glUniformMatrix4x2fv(int, int, boolean, float[], int);
+    method public static void glUniformMatrix4x2fv(int, int, boolean, java.nio.FloatBuffer);
+    method public static void glUniformMatrix4x3fv(int, int, boolean, float[], int);
+    method public static void glUniformMatrix4x3fv(int, int, boolean, java.nio.FloatBuffer);
+    method public static boolean glUnmapBuffer(int);
+    method public static void glVertexAttribDivisor(int, int);
+    method public static void glVertexAttribI4i(int, int, int, int, int);
+    method public static void glVertexAttribI4iv(int, int[], int);
+    method public static void glVertexAttribI4iv(int, java.nio.IntBuffer);
+    method public static void glVertexAttribI4ui(int, int, int, int, int);
+    method public static void glVertexAttribI4uiv(int, int[], int);
+    method public static void glVertexAttribI4uiv(int, java.nio.IntBuffer);
+    method public static void glVertexAttribIPointer(int, int, int, int, java.nio.Buffer);
+    method public static void glVertexAttribIPointer(int, int, int, int, int);
+    method public static void glWaitSync(long, int, long);
+    field public static final int GL_ACTIVE_UNIFORM_BLOCKS = 35382; // 0x8a36
+    field public static final int GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH = 35381; // 0x8a35
+    field public static final int GL_ALREADY_SIGNALED = 37146; // 0x911a
+    field public static final int GL_ANY_SAMPLES_PASSED = 35887; // 0x8c2f
+    field public static final int GL_ANY_SAMPLES_PASSED_CONSERVATIVE = 36202; // 0x8d6a
+    field public static final int GL_BLUE = 6405; // 0x1905
+    field public static final int GL_BUFFER_ACCESS_FLAGS = 37151; // 0x911f
+    field public static final int GL_BUFFER_MAPPED = 35004; // 0x88bc
+    field public static final int GL_BUFFER_MAP_LENGTH = 37152; // 0x9120
+    field public static final int GL_BUFFER_MAP_OFFSET = 37153; // 0x9121
+    field public static final int GL_BUFFER_MAP_POINTER = 35005; // 0x88bd
+    field public static final int GL_COLOR = 6144; // 0x1800
+    field public static final int GL_COLOR_ATTACHMENT1 = 36065; // 0x8ce1
+    field public static final int GL_COLOR_ATTACHMENT10 = 36074; // 0x8cea
+    field public static final int GL_COLOR_ATTACHMENT11 = 36075; // 0x8ceb
+    field public static final int GL_COLOR_ATTACHMENT12 = 36076; // 0x8cec
+    field public static final int GL_COLOR_ATTACHMENT13 = 36077; // 0x8ced
+    field public static final int GL_COLOR_ATTACHMENT14 = 36078; // 0x8cee
+    field public static final int GL_COLOR_ATTACHMENT15 = 36079; // 0x8cef
+    field public static final int GL_COLOR_ATTACHMENT2 = 36066; // 0x8ce2
+    field public static final int GL_COLOR_ATTACHMENT3 = 36067; // 0x8ce3
+    field public static final int GL_COLOR_ATTACHMENT4 = 36068; // 0x8ce4
+    field public static final int GL_COLOR_ATTACHMENT5 = 36069; // 0x8ce5
+    field public static final int GL_COLOR_ATTACHMENT6 = 36070; // 0x8ce6
+    field public static final int GL_COLOR_ATTACHMENT7 = 36071; // 0x8ce7
+    field public static final int GL_COLOR_ATTACHMENT8 = 36072; // 0x8ce8
+    field public static final int GL_COLOR_ATTACHMENT9 = 36073; // 0x8ce9
+    field public static final int GL_COMPARE_REF_TO_TEXTURE = 34894; // 0x884e
+    field public static final int GL_COMPRESSED_R11_EAC = 37488; // 0x9270
+    field public static final int GL_COMPRESSED_RG11_EAC = 37490; // 0x9272
+    field public static final int GL_COMPRESSED_RGB8_ETC2 = 37492; // 0x9274
+    field public static final int GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 37494; // 0x9276
+    field public static final int GL_COMPRESSED_RGBA8_ETC2_EAC = 37496; // 0x9278
+    field public static final int GL_COMPRESSED_SIGNED_R11_EAC = 37489; // 0x9271
+    field public static final int GL_COMPRESSED_SIGNED_RG11_EAC = 37491; // 0x9273
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC = 37497; // 0x9279
+    field public static final int GL_COMPRESSED_SRGB8_ETC2 = 37493; // 0x9275
+    field public static final int GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 37495; // 0x9277
+    field public static final int GL_CONDITION_SATISFIED = 37148; // 0x911c
+    field public static final int GL_COPY_READ_BUFFER = 36662; // 0x8f36
+    field public static final int GL_COPY_READ_BUFFER_BINDING = 36662; // 0x8f36
+    field public static final int GL_COPY_WRITE_BUFFER = 36663; // 0x8f37
+    field public static final int GL_COPY_WRITE_BUFFER_BINDING = 36663; // 0x8f37
+    field public static final int GL_CURRENT_QUERY = 34917; // 0x8865
+    field public static final int GL_DEPTH = 6145; // 0x1801
+    field public static final int GL_DEPTH24_STENCIL8 = 35056; // 0x88f0
+    field public static final int GL_DEPTH32F_STENCIL8 = 36013; // 0x8cad
+    field public static final int GL_DEPTH_COMPONENT24 = 33190; // 0x81a6
+    field public static final int GL_DEPTH_COMPONENT32F = 36012; // 0x8cac
+    field public static final int GL_DEPTH_STENCIL = 34041; // 0x84f9
+    field public static final int GL_DEPTH_STENCIL_ATTACHMENT = 33306; // 0x821a
+    field public static final int GL_DRAW_BUFFER0 = 34853; // 0x8825
+    field public static final int GL_DRAW_BUFFER1 = 34854; // 0x8826
+    field public static final int GL_DRAW_BUFFER10 = 34863; // 0x882f
+    field public static final int GL_DRAW_BUFFER11 = 34864; // 0x8830
+    field public static final int GL_DRAW_BUFFER12 = 34865; // 0x8831
+    field public static final int GL_DRAW_BUFFER13 = 34866; // 0x8832
+    field public static final int GL_DRAW_BUFFER14 = 34867; // 0x8833
+    field public static final int GL_DRAW_BUFFER15 = 34868; // 0x8834
+    field public static final int GL_DRAW_BUFFER2 = 34855; // 0x8827
+    field public static final int GL_DRAW_BUFFER3 = 34856; // 0x8828
+    field public static final int GL_DRAW_BUFFER4 = 34857; // 0x8829
+    field public static final int GL_DRAW_BUFFER5 = 34858; // 0x882a
+    field public static final int GL_DRAW_BUFFER6 = 34859; // 0x882b
+    field public static final int GL_DRAW_BUFFER7 = 34860; // 0x882c
+    field public static final int GL_DRAW_BUFFER8 = 34861; // 0x882d
+    field public static final int GL_DRAW_BUFFER9 = 34862; // 0x882e
+    field public static final int GL_DRAW_FRAMEBUFFER = 36009; // 0x8ca9
+    field public static final int GL_DRAW_FRAMEBUFFER_BINDING = 36006; // 0x8ca6
+    field public static final int GL_DYNAMIC_COPY = 35050; // 0x88ea
+    field public static final int GL_DYNAMIC_READ = 35049; // 0x88e9
+    field public static final int GL_FLOAT_32_UNSIGNED_INT_24_8_REV = 36269; // 0x8dad
+    field public static final int GL_FLOAT_MAT2x3 = 35685; // 0x8b65
+    field public static final int GL_FLOAT_MAT2x4 = 35686; // 0x8b66
+    field public static final int GL_FLOAT_MAT3x2 = 35687; // 0x8b67
+    field public static final int GL_FLOAT_MAT3x4 = 35688; // 0x8b68
+    field public static final int GL_FLOAT_MAT4x2 = 35689; // 0x8b69
+    field public static final int GL_FLOAT_MAT4x3 = 35690; // 0x8b6a
+    field public static final int GL_FRAGMENT_SHADER_DERIVATIVE_HINT = 35723; // 0x8b8b
+    field public static final int GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE = 33301; // 0x8215
+    field public static final int GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE = 33300; // 0x8214
+    field public static final int GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING = 33296; // 0x8210
+    field public static final int GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE = 33297; // 0x8211
+    field public static final int GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE = 33302; // 0x8216
+    field public static final int GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE = 33299; // 0x8213
+    field public static final int GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE = 33298; // 0x8212
+    field public static final int GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE = 33303; // 0x8217
+    field public static final int GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER = 36052; // 0x8cd4
+    field public static final int GL_FRAMEBUFFER_DEFAULT = 33304; // 0x8218
+    field public static final int GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE = 36182; // 0x8d56
+    field public static final int GL_FRAMEBUFFER_UNDEFINED = 33305; // 0x8219
+    field public static final int GL_GREEN = 6404; // 0x1904
+    field public static final int GL_HALF_FLOAT = 5131; // 0x140b
+    field public static final int GL_INTERLEAVED_ATTRIBS = 35980; // 0x8c8c
+    field public static final int GL_INT_2_10_10_10_REV = 36255; // 0x8d9f
+    field public static final int GL_INT_SAMPLER_2D = 36298; // 0x8dca
+    field public static final int GL_INT_SAMPLER_2D_ARRAY = 36303; // 0x8dcf
+    field public static final int GL_INT_SAMPLER_3D = 36299; // 0x8dcb
+    field public static final int GL_INT_SAMPLER_CUBE = 36300; // 0x8dcc
+    field public static final int GL_INVALID_INDEX = -1; // 0xffffffff
+    field public static final int GL_MAJOR_VERSION = 33307; // 0x821b
+    field public static final int GL_MAP_FLUSH_EXPLICIT_BIT = 16; // 0x10
+    field public static final int GL_MAP_INVALIDATE_BUFFER_BIT = 8; // 0x8
+    field public static final int GL_MAP_INVALIDATE_RANGE_BIT = 4; // 0x4
+    field public static final int GL_MAP_READ_BIT = 1; // 0x1
+    field public static final int GL_MAP_UNSYNCHRONIZED_BIT = 32; // 0x20
+    field public static final int GL_MAP_WRITE_BIT = 2; // 0x2
+    field public static final int GL_MAX = 32776; // 0x8008
+    field public static final int GL_MAX_3D_TEXTURE_SIZE = 32883; // 0x8073
+    field public static final int GL_MAX_ARRAY_TEXTURE_LAYERS = 35071; // 0x88ff
+    field public static final int GL_MAX_COLOR_ATTACHMENTS = 36063; // 0x8cdf
+    field public static final int GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS = 35379; // 0x8a33
+    field public static final int GL_MAX_COMBINED_UNIFORM_BLOCKS = 35374; // 0x8a2e
+    field public static final int GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS = 35377; // 0x8a31
+    field public static final int GL_MAX_DRAW_BUFFERS = 34852; // 0x8824
+    field public static final int GL_MAX_ELEMENTS_INDICES = 33001; // 0x80e9
+    field public static final int GL_MAX_ELEMENTS_VERTICES = 33000; // 0x80e8
+    field public static final int GL_MAX_ELEMENT_INDEX = 36203; // 0x8d6b
+    field public static final int GL_MAX_FRAGMENT_INPUT_COMPONENTS = 37157; // 0x9125
+    field public static final int GL_MAX_FRAGMENT_UNIFORM_BLOCKS = 35373; // 0x8a2d
+    field public static final int GL_MAX_FRAGMENT_UNIFORM_COMPONENTS = 35657; // 0x8b49
+    field public static final int GL_MAX_PROGRAM_TEXEL_OFFSET = 35077; // 0x8905
+    field public static final int GL_MAX_SAMPLES = 36183; // 0x8d57
+    field public static final int GL_MAX_SERVER_WAIT_TIMEOUT = 37137; // 0x9111
+    field public static final int GL_MAX_TEXTURE_LOD_BIAS = 34045; // 0x84fd
+    field public static final int GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS = 35978; // 0x8c8a
+    field public static final int GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS = 35979; // 0x8c8b
+    field public static final int GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS = 35968; // 0x8c80
+    field public static final int GL_MAX_UNIFORM_BLOCK_SIZE = 35376; // 0x8a30
+    field public static final int GL_MAX_UNIFORM_BUFFER_BINDINGS = 35375; // 0x8a2f
+    field public static final int GL_MAX_VARYING_COMPONENTS = 35659; // 0x8b4b
+    field public static final int GL_MAX_VERTEX_OUTPUT_COMPONENTS = 37154; // 0x9122
+    field public static final int GL_MAX_VERTEX_UNIFORM_BLOCKS = 35371; // 0x8a2b
+    field public static final int GL_MAX_VERTEX_UNIFORM_COMPONENTS = 35658; // 0x8b4a
+    field public static final int GL_MIN = 32775; // 0x8007
+    field public static final int GL_MINOR_VERSION = 33308; // 0x821c
+    field public static final int GL_MIN_PROGRAM_TEXEL_OFFSET = 35076; // 0x8904
+    field public static final int GL_NUM_EXTENSIONS = 33309; // 0x821d
+    field public static final int GL_NUM_PROGRAM_BINARY_FORMATS = 34814; // 0x87fe
+    field public static final int GL_NUM_SAMPLE_COUNTS = 37760; // 0x9380
+    field public static final int GL_OBJECT_TYPE = 37138; // 0x9112
+    field public static final int GL_PACK_ROW_LENGTH = 3330; // 0xd02
+    field public static final int GL_PACK_SKIP_PIXELS = 3332; // 0xd04
+    field public static final int GL_PACK_SKIP_ROWS = 3331; // 0xd03
+    field public static final int GL_PIXEL_PACK_BUFFER = 35051; // 0x88eb
+    field public static final int GL_PIXEL_PACK_BUFFER_BINDING = 35053; // 0x88ed
+    field public static final int GL_PIXEL_UNPACK_BUFFER = 35052; // 0x88ec
+    field public static final int GL_PIXEL_UNPACK_BUFFER_BINDING = 35055; // 0x88ef
+    field public static final int GL_PRIMITIVE_RESTART_FIXED_INDEX = 36201; // 0x8d69
+    field public static final int GL_PROGRAM_BINARY_FORMATS = 34815; // 0x87ff
+    field public static final int GL_PROGRAM_BINARY_LENGTH = 34625; // 0x8741
+    field public static final int GL_PROGRAM_BINARY_RETRIEVABLE_HINT = 33367; // 0x8257
+    field public static final int GL_QUERY_RESULT = 34918; // 0x8866
+    field public static final int GL_QUERY_RESULT_AVAILABLE = 34919; // 0x8867
+    field public static final int GL_R11F_G11F_B10F = 35898; // 0x8c3a
+    field public static final int GL_R16F = 33325; // 0x822d
+    field public static final int GL_R16I = 33331; // 0x8233
+    field public static final int GL_R16UI = 33332; // 0x8234
+    field public static final int GL_R32F = 33326; // 0x822e
+    field public static final int GL_R32I = 33333; // 0x8235
+    field public static final int GL_R32UI = 33334; // 0x8236
+    field public static final int GL_R8 = 33321; // 0x8229
+    field public static final int GL_R8I = 33329; // 0x8231
+    field public static final int GL_R8UI = 33330; // 0x8232
+    field public static final int GL_R8_SNORM = 36756; // 0x8f94
+    field public static final int GL_RASTERIZER_DISCARD = 35977; // 0x8c89
+    field public static final int GL_READ_BUFFER = 3074; // 0xc02
+    field public static final int GL_READ_FRAMEBUFFER = 36008; // 0x8ca8
+    field public static final int GL_READ_FRAMEBUFFER_BINDING = 36010; // 0x8caa
+    field public static final int GL_RED = 6403; // 0x1903
+    field public static final int GL_RED_INTEGER = 36244; // 0x8d94
+    field public static final int GL_RENDERBUFFER_SAMPLES = 36011; // 0x8cab
+    field public static final int GL_RG = 33319; // 0x8227
+    field public static final int GL_RG16F = 33327; // 0x822f
+    field public static final int GL_RG16I = 33337; // 0x8239
+    field public static final int GL_RG16UI = 33338; // 0x823a
+    field public static final int GL_RG32F = 33328; // 0x8230
+    field public static final int GL_RG32I = 33339; // 0x823b
+    field public static final int GL_RG32UI = 33340; // 0x823c
+    field public static final int GL_RG8 = 33323; // 0x822b
+    field public static final int GL_RG8I = 33335; // 0x8237
+    field public static final int GL_RG8UI = 33336; // 0x8238
+    field public static final int GL_RG8_SNORM = 36757; // 0x8f95
+    field public static final int GL_RGB10_A2 = 32857; // 0x8059
+    field public static final int GL_RGB10_A2UI = 36975; // 0x906f
+    field public static final int GL_RGB16F = 34843; // 0x881b
+    field public static final int GL_RGB16I = 36233; // 0x8d89
+    field public static final int GL_RGB16UI = 36215; // 0x8d77
+    field public static final int GL_RGB32F = 34837; // 0x8815
+    field public static final int GL_RGB32I = 36227; // 0x8d83
+    field public static final int GL_RGB32UI = 36209; // 0x8d71
+    field public static final int GL_RGB8 = 32849; // 0x8051
+    field public static final int GL_RGB8I = 36239; // 0x8d8f
+    field public static final int GL_RGB8UI = 36221; // 0x8d7d
+    field public static final int GL_RGB8_SNORM = 36758; // 0x8f96
+    field public static final int GL_RGB9_E5 = 35901; // 0x8c3d
+    field public static final int GL_RGBA16F = 34842; // 0x881a
+    field public static final int GL_RGBA16I = 36232; // 0x8d88
+    field public static final int GL_RGBA16UI = 36214; // 0x8d76
+    field public static final int GL_RGBA32F = 34836; // 0x8814
+    field public static final int GL_RGBA32I = 36226; // 0x8d82
+    field public static final int GL_RGBA32UI = 36208; // 0x8d70
+    field public static final int GL_RGBA8 = 32856; // 0x8058
+    field public static final int GL_RGBA8I = 36238; // 0x8d8e
+    field public static final int GL_RGBA8UI = 36220; // 0x8d7c
+    field public static final int GL_RGBA8_SNORM = 36759; // 0x8f97
+    field public static final int GL_RGBA_INTEGER = 36249; // 0x8d99
+    field public static final int GL_RGB_INTEGER = 36248; // 0x8d98
+    field public static final int GL_RG_INTEGER = 33320; // 0x8228
+    field public static final int GL_SAMPLER_2D_ARRAY = 36289; // 0x8dc1
+    field public static final int GL_SAMPLER_2D_ARRAY_SHADOW = 36292; // 0x8dc4
+    field public static final int GL_SAMPLER_2D_SHADOW = 35682; // 0x8b62
+    field public static final int GL_SAMPLER_3D = 35679; // 0x8b5f
+    field public static final int GL_SAMPLER_BINDING = 35097; // 0x8919
+    field public static final int GL_SAMPLER_CUBE_SHADOW = 36293; // 0x8dc5
+    field public static final int GL_SEPARATE_ATTRIBS = 35981; // 0x8c8d
+    field public static final int GL_SIGNALED = 37145; // 0x9119
+    field public static final int GL_SIGNED_NORMALIZED = 36764; // 0x8f9c
+    field public static final int GL_SRGB = 35904; // 0x8c40
+    field public static final int GL_SRGB8 = 35905; // 0x8c41
+    field public static final int GL_SRGB8_ALPHA8 = 35907; // 0x8c43
+    field public static final int GL_STATIC_COPY = 35046; // 0x88e6
+    field public static final int GL_STATIC_READ = 35045; // 0x88e5
+    field public static final int GL_STENCIL = 6146; // 0x1802
+    field public static final int GL_STREAM_COPY = 35042; // 0x88e2
+    field public static final int GL_STREAM_READ = 35041; // 0x88e1
+    field public static final int GL_SYNC_CONDITION = 37139; // 0x9113
+    field public static final int GL_SYNC_FENCE = 37142; // 0x9116
+    field public static final int GL_SYNC_FLAGS = 37141; // 0x9115
+    field public static final int GL_SYNC_FLUSH_COMMANDS_BIT = 1; // 0x1
+    field public static final int GL_SYNC_GPU_COMMANDS_COMPLETE = 37143; // 0x9117
+    field public static final int GL_SYNC_STATUS = 37140; // 0x9114
+    field public static final int GL_TEXTURE_2D_ARRAY = 35866; // 0x8c1a
+    field public static final int GL_TEXTURE_3D = 32879; // 0x806f
+    field public static final int GL_TEXTURE_BASE_LEVEL = 33084; // 0x813c
+    field public static final int GL_TEXTURE_BINDING_2D_ARRAY = 35869; // 0x8c1d
+    field public static final int GL_TEXTURE_BINDING_3D = 32874; // 0x806a
+    field public static final int GL_TEXTURE_COMPARE_FUNC = 34893; // 0x884d
+    field public static final int GL_TEXTURE_COMPARE_MODE = 34892; // 0x884c
+    field public static final int GL_TEXTURE_IMMUTABLE_FORMAT = 37167; // 0x912f
+    field public static final int GL_TEXTURE_IMMUTABLE_LEVELS = 33503; // 0x82df
+    field public static final int GL_TEXTURE_MAX_LEVEL = 33085; // 0x813d
+    field public static final int GL_TEXTURE_MAX_LOD = 33083; // 0x813b
+    field public static final int GL_TEXTURE_MIN_LOD = 33082; // 0x813a
+    field public static final int GL_TEXTURE_SWIZZLE_A = 36421; // 0x8e45
+    field public static final int GL_TEXTURE_SWIZZLE_B = 36420; // 0x8e44
+    field public static final int GL_TEXTURE_SWIZZLE_G = 36419; // 0x8e43
+    field public static final int GL_TEXTURE_SWIZZLE_R = 36418; // 0x8e42
+    field public static final int GL_TEXTURE_WRAP_R = 32882; // 0x8072
+    field public static final int GL_TIMEOUT_EXPIRED = 37147; // 0x911b
+    field public static final long GL_TIMEOUT_IGNORED = -1L; // 0xffffffffffffffffL
+    field public static final int GL_TRANSFORM_FEEDBACK = 36386; // 0x8e22
+    field public static final int GL_TRANSFORM_FEEDBACK_ACTIVE = 36388; // 0x8e24
+    field public static final int GL_TRANSFORM_FEEDBACK_BINDING = 36389; // 0x8e25
+    field public static final int GL_TRANSFORM_FEEDBACK_BUFFER = 35982; // 0x8c8e
+    field public static final int GL_TRANSFORM_FEEDBACK_BUFFER_BINDING = 35983; // 0x8c8f
+    field public static final int GL_TRANSFORM_FEEDBACK_BUFFER_MODE = 35967; // 0x8c7f
+    field public static final int GL_TRANSFORM_FEEDBACK_BUFFER_SIZE = 35973; // 0x8c85
+    field public static final int GL_TRANSFORM_FEEDBACK_BUFFER_START = 35972; // 0x8c84
+    field public static final int GL_TRANSFORM_FEEDBACK_PAUSED = 36387; // 0x8e23
+    field public static final int GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN = 35976; // 0x8c88
+    field public static final int GL_TRANSFORM_FEEDBACK_VARYINGS = 35971; // 0x8c83
+    field public static final int GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH = 35958; // 0x8c76
+    field public static final int GL_UNIFORM_ARRAY_STRIDE = 35388; // 0x8a3c
+    field public static final int GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS = 35394; // 0x8a42
+    field public static final int GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES = 35395; // 0x8a43
+    field public static final int GL_UNIFORM_BLOCK_BINDING = 35391; // 0x8a3f
+    field public static final int GL_UNIFORM_BLOCK_DATA_SIZE = 35392; // 0x8a40
+    field public static final int GL_UNIFORM_BLOCK_INDEX = 35386; // 0x8a3a
+    field public static final int GL_UNIFORM_BLOCK_NAME_LENGTH = 35393; // 0x8a41
+    field public static final int GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER = 35398; // 0x8a46
+    field public static final int GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER = 35396; // 0x8a44
+    field public static final int GL_UNIFORM_BUFFER = 35345; // 0x8a11
+    field public static final int GL_UNIFORM_BUFFER_BINDING = 35368; // 0x8a28
+    field public static final int GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT = 35380; // 0x8a34
+    field public static final int GL_UNIFORM_BUFFER_SIZE = 35370; // 0x8a2a
+    field public static final int GL_UNIFORM_BUFFER_START = 35369; // 0x8a29
+    field public static final int GL_UNIFORM_IS_ROW_MAJOR = 35390; // 0x8a3e
+    field public static final int GL_UNIFORM_MATRIX_STRIDE = 35389; // 0x8a3d
+    field public static final int GL_UNIFORM_NAME_LENGTH = 35385; // 0x8a39
+    field public static final int GL_UNIFORM_OFFSET = 35387; // 0x8a3b
+    field public static final int GL_UNIFORM_SIZE = 35384; // 0x8a38
+    field public static final int GL_UNIFORM_TYPE = 35383; // 0x8a37
+    field public static final int GL_UNPACK_IMAGE_HEIGHT = 32878; // 0x806e
+    field public static final int GL_UNPACK_ROW_LENGTH = 3314; // 0xcf2
+    field public static final int GL_UNPACK_SKIP_IMAGES = 32877; // 0x806d
+    field public static final int GL_UNPACK_SKIP_PIXELS = 3316; // 0xcf4
+    field public static final int GL_UNPACK_SKIP_ROWS = 3315; // 0xcf3
+    field public static final int GL_UNSIGNALED = 37144; // 0x9118
+    field public static final int GL_UNSIGNED_INT_10F_11F_11F_REV = 35899; // 0x8c3b
+    field public static final int GL_UNSIGNED_INT_24_8 = 34042; // 0x84fa
+    field public static final int GL_UNSIGNED_INT_2_10_10_10_REV = 33640; // 0x8368
+    field public static final int GL_UNSIGNED_INT_5_9_9_9_REV = 35902; // 0x8c3e
+    field public static final int GL_UNSIGNED_INT_SAMPLER_2D = 36306; // 0x8dd2
+    field public static final int GL_UNSIGNED_INT_SAMPLER_2D_ARRAY = 36311; // 0x8dd7
+    field public static final int GL_UNSIGNED_INT_SAMPLER_3D = 36307; // 0x8dd3
+    field public static final int GL_UNSIGNED_INT_SAMPLER_CUBE = 36308; // 0x8dd4
+    field public static final int GL_UNSIGNED_INT_VEC2 = 36294; // 0x8dc6
+    field public static final int GL_UNSIGNED_INT_VEC3 = 36295; // 0x8dc7
+    field public static final int GL_UNSIGNED_INT_VEC4 = 36296; // 0x8dc8
+    field public static final int GL_UNSIGNED_NORMALIZED = 35863; // 0x8c17
+    field public static final int GL_VERTEX_ARRAY_BINDING = 34229; // 0x85b5
+    field public static final int GL_VERTEX_ATTRIB_ARRAY_DIVISOR = 35070; // 0x88fe
+    field public static final int GL_VERTEX_ATTRIB_ARRAY_INTEGER = 35069; // 0x88fd
+    field public static final int GL_WAIT_FAILED = 37149; // 0x911d
+  }
+
   public class GLException extends java.lang.RuntimeException {
     ctor public GLException(int);
     ctor public GLException(int, java.lang.String);
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 0668be6..90bcb0f 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -12,6 +12,7 @@
 #include <utils/Log.h>
 #include <cutils/process_name.h>
 #include <cutils/memory.h>
+#include <cutils/trace.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <sys/personality.h>
 
@@ -95,6 +96,9 @@
 
     virtual void onZygoteInit()
     {
+        // Re-enable tracing now that we're no longer in Zygote.
+        atrace_set_tracing_enabled(true);
+
         sp<ProcessState> proc = ProcessState::self();
         ALOGV("App process: starting thread pool.\n");
         proc->startThreadPool();
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index a7543a8..8d994c4 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -427,22 +427,48 @@
     public String[] kind;
 
     /**
-     * Extra key for people values (type TBD).
-     *
+     * Additional semantic data to be carried around with this Notification.
      * @hide
      */
-    public static final String EXTRA_PEOPLE = "android.people";
+    public Bundle extras = new Bundle();
+
+    // extras keys for Builder inputs
     /** @hide */
     public static final String EXTRA_TITLE = "android.title";
     /** @hide */
+    public static final String EXTRA_TITLE_BIG = EXTRA_TITLE + ".big";
+    /** @hide */
     public static final String EXTRA_TEXT = "android.text";
     /** @hide */
-    public static final String EXTRA_SUBTEXT = "android.subtext";
+    public static final String EXTRA_SUB_TEXT = "android.subText";
+    /** @hide */
+    public static final String EXTRA_INFO_TEXT = "android.infoText";
+    /** @hide */
+    public static final String EXTRA_SUMMARY_TEXT = "android.summaryText";
     /** @hide */
     public static final String EXTRA_SMALL_ICON = "android.icon";
-
     /** @hide */
-    public Bundle extras = new Bundle();
+    public static final String EXTRA_LARGE_ICON = "android.largeIcon";
+    /** @hide */
+    public static final String EXTRA_LARGE_ICON_BIG = EXTRA_LARGE_ICON + ".big";
+    /** @hide */
+    public static final String EXTRA_PROGRESS = "android.progress";
+    /** @hide */
+    public static final String EXTRA_PROGRESS_MAX = "android.progressMax";
+    /** @hide */
+    public static final String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
+    /** @hide */
+    public static final String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
+    /** @hide */
+    public static final String EXTRA_SHOW_WHEN = "android.showWhen";
+    /** @hide from BigPictureStyle */
+    public static final String EXTRA_PICTURE = "android.picture";
+    /** @hide from InboxStyle */
+    public static final String EXTRA_TEXT_LINES = "android.textLines";
+
+    // extras keys for other interesting pieces of information
+    /** @hide */
+    public static final String EXTRA_PEOPLE = "android.people";
 
     /**
      * Structure to encapsulate an "action", including title and icon, that can be attached to a Notification.
@@ -1621,19 +1647,29 @@
                 mActions.toArray(n.actions);
             }
 
-            n.extras = mExtras != null ? new Bundle(mExtras) : new Bundle();
-
-            // Store original information used in the construction of this object
-            n.extras.putCharSequence(EXTRA_TITLE, mContentTitle);
-            n.extras.putCharSequence(EXTRA_TEXT, mContentText);
-            n.extras.putCharSequence(EXTRA_SUBTEXT, mSubText);
-            n.extras.putInt(EXTRA_SMALL_ICON, mSmallIcon);
-            //n.extras.putByteArray(EXTRA_LARGE_ICON, ...
-
             return n;
         }
 
         /**
+         * Capture, in the provided bundle, semantic information used in the construction of
+         * this Notification object.
+         * @hide
+         */
+        public void addExtras(Bundle extras) {
+            // Store original information used in the construction of this object
+            extras.putCharSequence(EXTRA_TITLE, mContentTitle);
+            extras.putCharSequence(EXTRA_TEXT, mContentText);
+            extras.putCharSequence(EXTRA_SUB_TEXT, mSubText);
+            extras.putCharSequence(EXTRA_INFO_TEXT, mContentInfo);
+            extras.putInt(EXTRA_SMALL_ICON, mSmallIcon);
+            extras.putInt(EXTRA_PROGRESS, mProgress);
+            extras.putInt(EXTRA_PROGRESS_MAX, mProgressMax);
+            extras.putBoolean(EXTRA_PROGRESS_INDETERMINATE, mProgressIndeterminate);
+            extras.putBoolean(EXTRA_SHOW_CHRONOMETER, mUseChronometer);
+            extras.putBoolean(EXTRA_SHOW_WHEN, mShowWhen);
+        }
+
+        /**
          * @deprecated Use {@link #build()} instead.
          */
         @Deprecated
@@ -1646,11 +1682,22 @@
          * object.
          */
         public Notification build() {
+            final Notification n;
+
             if (mStyle != null) {
-                return mStyle.build();
+                n = mStyle.build();
             } else {
-                return buildUnstyled();
+                n = buildUnstyled();
             }
+
+            n.extras = mExtras != null ? new Bundle(mExtras) : new Bundle();
+
+            addExtras(n.extras);
+            if (mStyle != null) {
+                mStyle.addExtras(n.extras);
+            }
+
+            return n;
         }
 
         /**
@@ -1664,7 +1711,6 @@
         }
     }
 
-
     /**
      * An object that can apply a rich notification style to a {@link Notification.Builder}
      * object.
@@ -1739,6 +1785,18 @@
             return contentView;
         }
 
+        /**
+         * @hide
+         */
+        public void addExtras(Bundle extras) {
+            if (mSummaryTextSet) {
+                extras.putCharSequence(EXTRA_SUMMARY_TEXT, mSummaryText);
+            }
+            if (mBigContentTitle != null) {
+                extras.putCharSequence(EXTRA_TITLE_BIG, mBigContentTitle);
+            }
+        }
+
         public abstract Notification build();
     }
 
@@ -1813,6 +1871,18 @@
             return contentView;
         }
 
+        /**
+         * @hide
+         */
+        public void addExtras(Bundle extras) {
+            super.addExtras(extras);
+
+            if (mBigLargeIconSet) {
+                extras.putParcelable(EXTRA_LARGE_ICON_BIG, mBigLargeIcon);
+            }
+            extras.putParcelable(EXTRA_PICTURE, mPicture);
+        }
+
         @Override
         public Notification build() {
             checkBuilder();
@@ -1878,6 +1948,15 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
+        public void addExtras(Bundle extras) {
+            super.addExtras(extras);
+
+            extras.putCharSequence(EXTRA_TEXT, mBigText);
+        }
+
         private RemoteViews makeBigContentView() {
             // Remove the content text so line3 only shows if you have a summary
             final boolean hadThreeLines = (mBuilder.mContentText != null && mBuilder.mSubText != null);
@@ -1964,6 +2043,15 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
+        public void addExtras(Bundle extras) {
+            super.addExtras(extras);
+            CharSequence[] a = new CharSequence[mTexts.size()];
+            extras.putCharSequenceArray(EXTRA_TEXT_LINES, mTexts.toArray(a));
+        }
+
         private RemoteViews makeBigContentView() {
             // Remove the content text so line3 disappears unless you have a summary
             mBuilder.mContentText = null;
@@ -2005,13 +2093,6 @@
             Notification wip = mBuilder.buildUnstyled();
             wip.bigContentView = makeBigContentView();
 
-            StringBuilder builder = new StringBuilder();
-            for (CharSequence str : mTexts) {
-                builder.append(str);
-                builder.append("\n");
-            }
-            wip.extras.putCharSequence(EXTRA_TEXT, builder);
-
             return wip;
         }
     }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index ff0bea8..64eaf9b 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1898,11 +1898,12 @@
                     false)) {
                 owner.mRequiredForAllUsers = true;
             }
-            String restrictedAccountType = sa.getString(com.android.internal.R.styleable
-                    .AndroidManifestApplication_restrictedAccountType);
-            if (restrictedAccountType != null && restrictedAccountType.length() > 0) {
-                owner.mRestrictedAccountType = restrictedAccountType;
-            }
+        }
+
+        String restrictedAccountType = sa.getString(com.android.internal.R.styleable
+                .AndroidManifestApplication_restrictedAccountType);
+        if (restrictedAccountType != null && restrictedAccountType.length() > 0) {
+            owner.mRestrictedAccountType = restrictedAccountType;
         }
 
         String requiredAccountType = sa.getString(com.android.internal.R.styleable
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 074f8fe..71a5382 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -188,6 +188,8 @@
     // Upon detection of an event, the sensor deactivates itself and then sends a single event.
     static int REPORTING_MODE_ONE_SHOT = 3;
 
+    // TODO(): The following arrays are fragile and error-prone. This needs to be refactored.
+
     // Note: This needs to be updated, whenever a new sensor is added.
     private static int[] sSensorReportingModes = {
             REPORTING_MODE_CONTINUOUS, REPORTING_MODE_CONTINUOUS, REPORTING_MODE_CONTINUOUS,
@@ -201,7 +203,7 @@
     // Holds the maximum length of the values array associated with {@link SensorEvent} or
     // {@link TriggerEvent} for the Sensor
     private static int[] sMaxLengthValuesArray = {
-            3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 3, 3,
+            3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 3,
             6, 4, 6, 1 };
 
     static int getReportingMode(Sensor sensor) {
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 480fe7d..5e20dec 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -244,12 +244,17 @@
             // The signature cert matches a trusted key.  Now verify that
             // the digest in the cert matches the actual file data.
 
-            // The verifier in recovery *only* handles SHA1withRSA
-            // signatures.  SignApk.java always uses SHA1withRSA, no
-            // matter what the cert says to use.  Ignore
-            // cert.getSigAlgName(), and instead use whatever
-            // algorithm is used by the signature (which should be
-            // SHA1withRSA).
+            // The verifier in recovery only handles SHA1withRSA and
+            // SHA256withRSA signatures.  SignApk chooses which to use
+            // based on the signature algorithm of the cert:
+            //
+            //    "SHA256withRSA" cert -> "SHA256withRSA" signature
+            //    "SHA1withRSA" cert   -> "SHA1withRSA" signature
+            //    "MD5withRSA" cert    -> "SHA1withRSA" signature (for backwards compatibility)
+            //    any other cert       -> SignApk fails
+            //
+            // Here we ignore whatever the cert says, and instead use
+            // whatever algorithm is used by the signature.
 
             String da = sigInfo.getDigestAlgorithm();
             String dea = sigInfo.getDigestEncryptionAlgorithm();
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index 617f490..3307a8c 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -79,6 +79,7 @@
     private static native void nativeAsyncTraceBegin(long tag, String name, int cookie);
     private static native void nativeAsyncTraceEnd(long tag, String name, int cookie);
     private static native void nativeSetAppTracingAllowed(boolean allowed);
+    private static native void nativeSetTracingEnabled(boolean allowed);
 
     static {
         // We configure two separate change callbacks, one in Trace.cpp and one here.  The
@@ -115,10 +116,6 @@
      */
     private static long cacheEnabledTags() {
         long tags = nativeGetEnabledTags();
-        if (tags == TRACE_TAG_NOT_READY) {
-            Log.w(TAG, "Unexpected value from nativeGetEnabledTags: " + tags);
-            // keep going
-        }
         sEnabledTags = tags;
         return tags;
     }
@@ -169,6 +166,22 @@
     }
 
     /**
+     * Set whether tracing is enabled in this process.  Tracing is disabled shortly after Zygote
+     * initializes and re-enabled after processes fork from Zygote.  This is done because Zygote
+     * has no way to be notified about changes to the tracing tags, and if Zygote ever reads and
+     * caches the tracing tags, forked processes will inherit those stale tags.
+     *
+     * @hide
+     */
+    public static void setTracingEnabled(boolean enabled) {
+        nativeSetTracingEnabled(enabled);
+
+        // Setting whether tracing is enabled may change the tags, so we update the cached tags
+        // here.
+        cacheEnabledTags();
+    }
+
+    /**
      * Writes a trace message to indicate that a given section of code has
      * begun. Must be followed by a call to {@link #traceEnd} using the same
      * tag.
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 5d0f523..14fa9cb 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -480,6 +480,7 @@
                 if (!getContext().getResources().getCompatibilityInfo().supportsScreen()) {
                     mLayout.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
                 }
+                mLayout.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
 
                 if (mWindow == null) {
                     Display display = getDisplay();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index a8e66ec..789fe40 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2479,6 +2479,18 @@
 
     /**
      * @hide
+     *
+     * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
+     * out of the public fields to keep the undefined bits out of the developer's way.
+     *
+     * Flag to specify that the status bar should temporarily overlay underlying content
+     * that is otherwise assuming the status bar is hidden.  The status bar will typically
+     * have some degree of transparency while in this temporary overlay mode.
+     */
+    public static final int STATUS_BAR_OVERLAY = 0x04000000;
+
+    /**
+     * @hide
      */
     public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x0000FFFF;
 
diff --git a/core/java/android/view/ViewGroupOverlay.java b/core/java/android/view/ViewGroupOverlay.java
index c1b24f2..16afc5d 100644
--- a/core/java/android/view/ViewGroupOverlay.java
+++ b/core/java/android/view/ViewGroupOverlay.java
@@ -47,7 +47,8 @@
      * animation effect.</p>
      *
      * <p>If the view has a parent, the view will be removed from that parent
-     * before being added to the overlay. Also, the view will be repositioned
+     * before being added to the overlay. Also, if that parent is attached
+     * in the current view hierarchy, the view will be repositioned
      * such that it is in the same relative location inside the activity. For
      * example, if the view's current parent lies 100 pixels to the right
      * and 200 pixels down from the origin of the overlay's
diff --git a/core/java/android/view/ViewOverlay.java b/core/java/android/view/ViewOverlay.java
index 78e2597..fe5b990 100644
--- a/core/java/android/view/ViewOverlay.java
+++ b/core/java/android/view/ViewOverlay.java
@@ -157,7 +157,8 @@
         public void add(View child) {
             if (child.getParent() instanceof ViewGroup) {
                 ViewGroup parent = (ViewGroup) child.getParent();
-                if (parent != mHostView) {
+                if (parent != mHostView && parent.getParent() != null &&
+                        parent.mAttachInfo != null) {
                     // Moving to different container; figure out how to position child such that
                     // it is in the same location on the screen
                     int[] parentLocation = new int[2];
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index cd39856..5e52107 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1020,6 +1020,12 @@
         public static final int PRIVATE_FLAG_FORCE_SHOW_NAV_BAR = 0x00000020;
 
         /**
+         * Never animate position changes of the window.
+         *
+         * {@hide} */
+        public static final int PRIVATE_FLAG_NO_MOVE_ANIMATION = 0x00000040;
+
+        /**
          * Control flags that are private to the platform.
          * @hide
          */
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index a326da2..312af71 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -17,10 +17,8 @@
 package android.webkit;
 
 import android.app.Activity;
-import android.app.AlertDialog;
 import android.content.ActivityNotFoundException;
 import android.content.Context;
-import android.content.DialogInterface;
 import android.content.Intent;
 import android.graphics.Bitmap;
 import android.net.Uri;
@@ -33,10 +31,6 @@
 import android.provider.Browser;
 import android.util.Log;
 import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.EditText;
-import android.widget.TextView;
 import com.android.internal.R;
 
 import java.net.MalformedURLException;
@@ -92,10 +86,7 @@
     private static final int CREATE_WINDOW                        = 109;
     private static final int CLOSE_WINDOW                         = 110;
     private static final int SAVE_PASSWORD                        = 111;
-    private static final int JS_ALERT                             = 112;
-    private static final int JS_CONFIRM                           = 113;
-    private static final int JS_PROMPT                            = 114;
-    private static final int JS_UNLOAD                            = 115;
+    private static final int JS_DIALOG                            = 112;
     private static final int ASYNC_KEYEVENTS                      = 116;
     private static final int DOWNLOAD_FILE                        = 118;
     private static final int REPORT_ERROR                         = 119;
@@ -566,188 +557,12 @@
                 }
                 break;
 
-            case JS_ALERT:
+            case JS_DIALOG:
                 if (mWebChromeClient != null) {
                     final JsResultReceiver receiver = (JsResultReceiver) msg.obj;
-                    final JsResult res = receiver.mJsResult;
-                    String message = msg.getData().getString("message");
-                    String url = msg.getData().getString("url");
-                    if (!mWebChromeClient.onJsAlert(mWebView.getWebView(), url, message,
-                            res)) {
-                        if (!canShowAlertDialog()) {
-                            res.cancel();
-                            receiver.setReady();
-                            break;
-                        }
-                        new AlertDialog.Builder(mContext)
-                                .setTitle(getJsDialogTitle(url))
-                                .setMessage(message)
-                                .setPositiveButton(R.string.ok,
-                                        new DialogInterface.OnClickListener() {
-                                            public void onClick(
-                                                    DialogInterface dialog,
-                                                    int which) {
-                                                res.confirm();
-                                            }
-                                        })
-                                .setOnCancelListener(
-                                        new DialogInterface.OnCancelListener() {
-                                            public void onCancel(
-                                                    DialogInterface dialog) {
-                                                res.cancel();
-                                            }
-                                        })
-                                .show();
-                    }
-                    receiver.setReady();
-                }
-                break;
-
-            case JS_CONFIRM:
-                if (mWebChromeClient != null) {
-                    final JsResultReceiver receiver = (JsResultReceiver) msg.obj;
-                    final JsResult res = receiver.mJsResult;
-                    String message = msg.getData().getString("message");
-                    String url = msg.getData().getString("url");
-                    if (!mWebChromeClient.onJsConfirm(mWebView.getWebView(), url, message,
-                            res)) {
-                        if (!canShowAlertDialog()) {
-                            res.cancel();
-                            receiver.setReady();
-                            break;
-                        }
-                        new AlertDialog.Builder(mContext)
-                                .setTitle(getJsDialogTitle(url))
-                                .setMessage(message)
-                                .setPositiveButton(R.string.ok,
-                                        new DialogInterface.OnClickListener() {
-                                            public void onClick(
-                                                    DialogInterface dialog,
-                                                    int which) {
-                                                res.confirm();
-                                            }})
-                                .setNegativeButton(R.string.cancel,
-                                        new DialogInterface.OnClickListener() {
-                                            public void onClick(
-                                                    DialogInterface dialog,
-                                                    int which) {
-                                                res.cancel();
-                                            }})
-                                .setOnCancelListener(
-                                        new DialogInterface.OnCancelListener() {
-                                            public void onCancel(
-                                                    DialogInterface dialog) {
-                                                res.cancel();
-                                            }
-                                        })
-                                .show();
-                    }
-                    // Tell the JsResult that it is ready for client
-                    // interaction.
-                    receiver.setReady();
-                }
-                break;
-
-            case JS_PROMPT:
-                if (mWebChromeClient != null) {
-                    final JsResultReceiver receiver = (JsResultReceiver) msg.obj;
-                    final JsPromptResult res = receiver.mJsResult;
-                    String message = msg.getData().getString("message");
-                    String defaultVal = msg.getData().getString("default");
-                    String url = msg.getData().getString("url");
-                    if (!mWebChromeClient.onJsPrompt(mWebView.getWebView(), url, message,
-                                defaultVal, res)) {
-                        if (!canShowAlertDialog()) {
-                            res.cancel();
-                            receiver.setReady();
-                            break;
-                        }
-                        final LayoutInflater factory = LayoutInflater
-                                .from(mContext);
-                        final View view = factory.inflate(R.layout.js_prompt,
-                                null);
-                        final EditText v = (EditText) view
-                                .findViewById(R.id.value);
-                        v.setText(defaultVal);
-                        ((TextView) view.findViewById(R.id.message))
-                                .setText(message);
-                        new AlertDialog.Builder(mContext)
-                                .setTitle(getJsDialogTitle(url))
-                                .setView(view)
-                                .setPositiveButton(R.string.ok,
-                                        new DialogInterface.OnClickListener() {
-                                            public void onClick(
-                                                    DialogInterface dialog,
-                                                    int whichButton) {
-                                                res.confirm(v.getText()
-                                                        .toString());
-                                            }
-                                        })
-                                .setNegativeButton(R.string.cancel,
-                                        new DialogInterface.OnClickListener() {
-                                            public void onClick(
-                                                    DialogInterface dialog,
-                                                    int whichButton) {
-                                                res.cancel();
-                                            }
-                                        })
-                                .setOnCancelListener(
-                                        new DialogInterface.OnCancelListener() {
-                                            public void onCancel(
-                                                    DialogInterface dialog) {
-                                                res.cancel();
-                                            }
-                                        })
-                                .show();
-                    }
-                    // Tell the JsResult that it is ready for client
-                    // interaction.
-                    receiver.setReady();
-                }
-                break;
-
-            case JS_UNLOAD:
-                if (mWebChromeClient != null) {
-                    final JsResultReceiver receiver = (JsResultReceiver) msg.obj;
-                    final JsResult res = receiver.mJsResult;
-                    String message = msg.getData().getString("message");
-                    String url = msg.getData().getString("url");
-                    if (!mWebChromeClient.onJsBeforeUnload(mWebView.getWebView(), url,
-                            message, res)) {
-                        if (!canShowAlertDialog()) {
-                            res.cancel();
-                            receiver.setReady();
-                            break;
-                        }
-                        final String m = mContext.getString(
-                                R.string.js_dialog_before_unload, message);
-                        new AlertDialog.Builder(mContext)
-                                .setMessage(m)
-                                .setPositiveButton(R.string.ok,
-                                        new DialogInterface.OnClickListener() {
-                                            public void onClick(
-                                                    DialogInterface dialog,
-                                                    int which) {
-                                                res.confirm();
-                                            }
-                                        })
-                                .setNegativeButton(R.string.cancel,
-                                        new DialogInterface.OnClickListener() {
-                                            public void onClick(
-                                                    DialogInterface dialog,
-                                                    int which) {
-                                                res.cancel();
-                                            }
-                                        })
-                                .setOnCancelListener(
-                                        new DialogInterface.OnCancelListener() {
-                                            @Override
-                                            public void onCancel(
-                                                    DialogInterface dialog) {
-                                                res.cancel();
-                                            }
-                                        })
-                                .show();
+                    JsDialogHelper helper = new JsDialogHelper(receiver.mJsResult, msg);
+                    if (!helper.invokeCallback(mWebChromeClient, mWebView.getWebView())) {
+                        helper.showDialog(mContext);
                     }
                     receiver.setReady();
                 }
@@ -757,7 +572,7 @@
                 if(mWebChromeClient != null) {
                     final JsResultReceiver receiver = (JsResultReceiver) msg.obj;
                     final JsResult res = receiver.mJsResult;
-                    if(mWebChromeClient.onJsTimeout()) {
+                    if (mWebChromeClient.onJsTimeout()) {
                         res.confirm();
                     } else {
                         res.cancel();
@@ -895,24 +710,6 @@
         sendMessage(obtainMessage(SWITCH_OUT_HISTORY));
     }
 
-    private String getJsDialogTitle(String url) {
-        String title = url;
-        if (URLUtil.isDataUrl(url)) {
-            // For data: urls, we just display 'JavaScript' similar to Safari.
-            title = mContext.getString(R.string.js_dialog_title_default);
-        } else {
-            try {
-                URL aUrl = new URL(url);
-                // For example: "The page at 'http://www.mit.edu' says:"
-                title = mContext.getString(R.string.js_dialog_title,
-                        aUrl.getProtocol() + "://" + aUrl.getHost());
-            } catch (MalformedURLException ex) {
-                // do nothing. just use the url as the title
-            }
-        }
-        return title;
-    }
-
     //--------------------------------------------------------------------------
     // WebViewClient functions.
     // NOTE: shouldOverrideKeyEvent is never called from the WebCore thread so
@@ -1332,9 +1129,10 @@
             return;
         }
         JsResultReceiver result = new JsResultReceiver();
-        Message alert = obtainMessage(JS_ALERT, result);
+        Message alert = obtainMessage(JS_DIALOG, result);
         alert.getData().putString("message", message);
         alert.getData().putString("url", url);
+        alert.getData().putInt("type", JsDialogHelper.ALERT);
         sendMessageToUiThreadSync(alert);
     }
 
@@ -1345,9 +1143,10 @@
             return false;
         }
         JsResultReceiver result = new JsResultReceiver();
-        Message confirm = obtainMessage(JS_CONFIRM, result);
+        Message confirm = obtainMessage(JS_DIALOG, result);
         confirm.getData().putString("message", message);
         confirm.getData().putString("url", url);
+        confirm.getData().putInt("type", JsDialogHelper.CONFIRM);
         sendMessageToUiThreadSync(confirm);
         return result.mJsResult.getResult();
     }
@@ -1359,10 +1158,11 @@
             return null;
         }
         JsResultReceiver result = new JsResultReceiver();
-        Message prompt = obtainMessage(JS_PROMPT, result);
+        Message prompt = obtainMessage(JS_DIALOG, result);
         prompt.getData().putString("message", message);
         prompt.getData().putString("default", defaultValue);
         prompt.getData().putString("url", url);
+        prompt.getData().putInt("type", JsDialogHelper.PROMPT);
         sendMessageToUiThreadSync(prompt);
         return result.mJsResult.getStringResult();
     }
@@ -1374,10 +1174,11 @@
             return true;
         }
         JsResultReceiver result = new JsResultReceiver();
-        Message confirm = obtainMessage(JS_UNLOAD, result);
-        confirm.getData().putString("message", message);
-        confirm.getData().putString("url", url);
-        sendMessageToUiThreadSync(confirm);
+        Message unload = obtainMessage(JS_DIALOG, result);
+        unload.getData().putString("message", message);
+        unload.getData().putString("url", url);
+        unload.getData().putInt("type", JsDialogHelper.UNLOAD);
+        sendMessageToUiThreadSync(unload);
         return result.mJsResult.getResult();
     }
 
@@ -1595,16 +1396,6 @@
         sendMessage(msg);
     }
 
-    boolean canShowAlertDialog() {
-        // We can only display the alert dialog if mContext is
-        // an Activity context.
-        // FIXME: Should we display dialogs if mContext does
-        // not have the window focus (e.g. if the user is viewing
-        // another Activity when the alert should be displayed?
-        // See bug 3166409
-        return mContext instanceof Activity;
-    }
-
     private synchronized void sendMessageToUiThreadSync(Message msg) {
         sendMessage(msg);
         WebCoreThreadWatchdog.pause();
diff --git a/core/java/android/webkit/JsDialogHelper.java b/core/java/android/webkit/JsDialogHelper.java
new file mode 100644
index 0000000..bb0339e
--- /dev/null
+++ b/core/java/android/webkit/JsDialogHelper.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2013 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 android.webkit;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Message;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+ * Helper class to create JavaScript dialogs. It is used by
+ * different WebView implementations.
+ *
+ * @hide Helper class for internal use
+ */
+public class JsDialogHelper {
+
+    private static final String TAG = "JsDialogHelper";
+
+    // Dialog types
+    public static final int ALERT   = 1;
+    public static final int CONFIRM = 2;
+    public static final int PROMPT  = 3;
+    public static final int UNLOAD  = 4;
+
+    private final String mDefaultValue;
+    private final JsPromptResult mResult;
+    private final String mMessage;
+    private final int mType;
+    private final String mUrl;
+
+    public JsDialogHelper(JsPromptResult result, int type, String defaultValue, String message,
+            String url) {
+        mResult = result;
+        mDefaultValue = defaultValue;
+        mMessage = message;
+        mType = type;
+        mUrl = url;
+    }
+
+    public JsDialogHelper(JsPromptResult result, Message msg) {
+        mResult = result;
+        mDefaultValue = msg.getData().getString("default");
+        mMessage = msg.getData().getString("message");
+        mType = msg.getData().getInt("type");
+        mUrl = msg.getData().getString("url");
+    }
+
+    public boolean invokeCallback(WebChromeClient client, WebView webView) {
+        switch (mType) {
+            case ALERT:
+                return client.onJsAlert(webView, mUrl, mMessage, mResult);
+            case CONFIRM:
+                return client.onJsConfirm(webView, mUrl, mMessage, mResult);
+            case UNLOAD:
+                return client.onJsBeforeUnload(webView, mUrl, mMessage, mResult);
+            case PROMPT:
+                return client.onJsPrompt(webView, mUrl, mMessage, mDefaultValue, mResult);
+            default:
+                throw new IllegalArgumentException("Unexpected type: " + mType);
+        }
+    }
+
+    public void showDialog(Context context) {
+        if (!canShowAlertDialog(context)) {
+            Log.w(TAG, "Cannot create a dialog, the WebView context is not an Activity");
+            mResult.cancel();
+            return;
+        }
+
+        String title, displayMessage;
+        int positiveTextId, negativeTextId;
+        if (mType == UNLOAD) {
+            title = context.getString(com.android.internal.R.string.js_dialog_before_unload_title);
+            displayMessage = context.getString(
+                    com.android.internal.R.string.js_dialog_before_unload, mMessage);
+            positiveTextId = com.android.internal.R.string.js_dialog_before_unload_positive_button;
+            negativeTextId = com.android.internal.R.string.js_dialog_before_unload_negative_button;
+        } else {
+            title = getJsDialogTitle(context);
+            displayMessage = mMessage;
+            positiveTextId = com.android.internal.R.string.ok;
+            negativeTextId = com.android.internal.R.string.cancel;
+        }
+        AlertDialog.Builder builder = new AlertDialog.Builder(context);
+        builder.setTitle(title);
+        builder.setOnCancelListener(new CancelListener());
+        if (mType != PROMPT) {
+            builder.setMessage(displayMessage);
+            builder.setPositiveButton(positiveTextId, new PositiveListener(null));
+        } else {
+            final View view = LayoutInflater.from(context).inflate(
+                    com.android.internal.R.layout.js_prompt, null);
+            EditText edit = ((EditText) view.findViewById(com.android.internal.R.id.value));
+            edit.setText(mDefaultValue);
+            builder.setPositiveButton(positiveTextId, new PositiveListener(edit));
+            ((TextView) view.findViewById(com.android.internal.R.id.message)).setText(mMessage);
+            builder.setView(view);
+        }
+        if (mType != ALERT) {
+            builder.setNegativeButton(negativeTextId, new CancelListener());
+        }
+        builder.show();
+    }
+
+    private class CancelListener implements DialogInterface.OnCancelListener,
+            DialogInterface.OnClickListener {
+        @Override
+        public void onCancel(DialogInterface dialog) {
+            mResult.cancel();
+        }
+        @Override
+        public void onClick(DialogInterface dialog, int which) {
+            mResult.cancel();
+        }
+    }
+
+    private class PositiveListener implements DialogInterface.OnClickListener {
+        private final EditText mEdit;
+
+        public PositiveListener(EditText edit) {
+            mEdit = edit;
+        }
+
+        @Override
+        public void onClick(DialogInterface dialog, int which) {
+            if (mEdit == null) {
+                mResult.confirm();
+            } else {
+                mResult.confirm(mEdit.getText().toString());
+            }
+        }
+    }
+
+    private String getJsDialogTitle(Context context) {
+        String title = mUrl;
+        if (URLUtil.isDataUrl(mUrl)) {
+            // For data: urls, we just display 'JavaScript' similar to Chrome.
+            title = context.getString(com.android.internal.R.string.js_dialog_title_default);
+        } else {
+            try {
+                URL alertUrl = new URL(mUrl);
+                // For example: "The page at 'http://www.mit.edu' says:"
+                title = context.getString(com.android.internal.R.string.js_dialog_title,
+                        alertUrl.getProtocol() + "://" + alertUrl.getHost());
+            } catch (MalformedURLException ex) {
+                // do nothing. just use the url as the title
+            }
+        }
+        return title;
+    }
+
+    private static boolean canShowAlertDialog(Context context) {
+        // We can only display the alert dialog if mContext is
+        // an Activity context.
+        // FIXME: Should we display dialogs if mContext does
+        // not have the window focus (e.g. if the user is viewing
+        // another Activity when the alert should be displayed) ?
+        // See bug 3166409
+        return context instanceof Activity;
+    }
+}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 94dadb4..c72853f 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2699,6 +2699,15 @@
         mLastTouchMode = touchMode;
     }
 
+    @Override
+    public void onRtlPropertiesChanged(int layoutDirection) {
+        super.onRtlPropertiesChanged(layoutDirection);
+
+        if (mFastScroller != null) {
+           mFastScroller.setScrollbarPosition(getVerticalScrollbarPosition());
+        }
+    }
+
     /**
      * Creates the ContextMenuInfo returned from {@link #getContextMenuInfo()}. This
      * methods knows the view, position and ID of the item that received the
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index d2139af..fc9c000 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -216,8 +216,22 @@
                 mHandler.removeCallbacks(mScrollFade);
                 break;
             case STATE_EXIT:
-                int viewWidth = mList.getWidth();
-                mList.invalidate(viewWidth - mThumbW, mThumbY, viewWidth, mThumbY + mThumbH);
+                final int viewWidth = mList.getWidth();
+                final int top = mThumbY;
+                final int bottom = mThumbY + mThumbH;
+                final int left;
+                final int right;
+                switch (mList.getLayoutDirection()) {
+                    case View.LAYOUT_DIRECTION_RTL:
+                        left = 0;
+                        right = mThumbW;
+                        break;
+                    case View.LAYOUT_DIRECTION_LTR:
+                    default:
+                        left = viewWidth - mThumbW;
+                        right = viewWidth;
+                }
+                mList.invalidate(left, top, right, bottom);
                 break;
         }
         mState = state;
@@ -398,10 +412,26 @@
         } else if (mState == STATE_EXIT) {
             if (alpha == 0) { // Done with exit
                 setState(STATE_NONE);
-            } else if (mTrackDrawable != null) {
-                mList.invalidate(viewWidth - mThumbW, 0, viewWidth, mList.getHeight());
             } else {
-                mList.invalidate(viewWidth - mThumbW, y, viewWidth, y + mThumbH);
+                final int left, right, top, bottom;
+                if (mTrackDrawable != null) {
+                    top = 0;
+                    bottom = mList.getHeight();
+                } else {
+                    top = y;
+                    bottom = y + mThumbH;
+                }
+                switch (mList.getLayoutDirection()) {
+                    case View.LAYOUT_DIRECTION_RTL:
+                        left = 0;
+                        right = mThumbW;
+                        break;
+                    case View.LAYOUT_DIRECTION_LTR:
+                    default:
+                        left = viewWidth - mThumbW;
+                        right = viewWidth;
+                }
+                mList.invalidate(left, top, right, bottom);
             }
         }
     }
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 206beb3..b0ab70d 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -986,15 +986,17 @@
 
     // Measurement
 
+    // Note: padding has already been removed from the supplied specs
     private void measureChildWithMargins2(View child, int parentWidthSpec, int parentHeightSpec,
             int childWidth, int childHeight) {
         int childWidthSpec = getChildMeasureSpec(parentWidthSpec,
-                mPaddingLeft + mPaddingRight + getTotalMargin(child, true), childWidth);
+                getTotalMargin(child, true), childWidth);
         int childHeightSpec = getChildMeasureSpec(parentHeightSpec,
-                mPaddingTop + mPaddingBottom + getTotalMargin(child, false), childHeight);
+                getTotalMargin(child, false), childHeight);
         child.measure(childWidthSpec, childHeightSpec);
     }
 
+    // Note: padding has already been removed from the supplied specs
     private void measureChildrenWithMargins(int widthSpec, int heightSpec, boolean firstPass) {
         for (int i = 0, N = getChildCount(); i < N; i++) {
             View c = getChildAt(i);
@@ -1021,6 +1023,11 @@
         }
     }
 
+    static int adjust(int measureSpec, int delta) {
+        return makeMeasureSpec(
+                MeasureSpec.getSize(measureSpec + delta),  MeasureSpec.getMode(measureSpec));
+    }
+
     @Override
     protected void onMeasure(int widthSpec, int heightSpec) {
         consistencyCheck();
@@ -1029,29 +1036,33 @@
          *  is  likely to have changed. We must invalidate if so. */
         invalidateValues();
 
-        measureChildrenWithMargins(widthSpec, heightSpec, true);
+        int hPadding = getPaddingLeft() + getPaddingRight();
+        int vPadding = getPaddingTop()  + getPaddingBottom();
 
-        int width, height;
+        int widthSpecSansPadding =  adjust( widthSpec, -hPadding);
+        int heightSpecSansPadding = adjust(heightSpec, -vPadding);
+
+        measureChildrenWithMargins(widthSpecSansPadding, heightSpecSansPadding, true);
+
+        int widthSansPadding;
+        int heightSansPadding;
 
         // Use the orientation property to decide which axis should be laid out first.
         if (orientation == HORIZONTAL) {
-            width = horizontalAxis.getMeasure(widthSpec);
-            measureChildrenWithMargins(widthSpec, heightSpec, false);
-            height = verticalAxis.getMeasure(heightSpec);
+            widthSansPadding = horizontalAxis.getMeasure(widthSpecSansPadding);
+            measureChildrenWithMargins(widthSpecSansPadding, heightSpecSansPadding, false);
+            heightSansPadding = verticalAxis.getMeasure(heightSpecSansPadding);
         } else {
-            height = verticalAxis.getMeasure(heightSpec);
-            measureChildrenWithMargins(widthSpec, heightSpec, false);
-            width = horizontalAxis.getMeasure(widthSpec);
+            heightSansPadding = verticalAxis.getMeasure(heightSpecSansPadding);
+            measureChildrenWithMargins(widthSpecSansPadding, heightSpecSansPadding, false);
+            widthSansPadding = horizontalAxis.getMeasure(widthSpecSansPadding);
         }
 
-        int hPadding = getPaddingLeft() + getPaddingRight();
-        int vPadding = getPaddingTop() + getPaddingBottom();
-
-        int measuredWidth = Math.max(hPadding + width, getSuggestedMinimumWidth());
-        int measuredHeight = Math.max(vPadding + height, getSuggestedMinimumHeight());
+        int measuredWidth  = Math.max(widthSansPadding  + hPadding, getSuggestedMinimumWidth());
+        int measuredHeight = Math.max(heightSansPadding + vPadding, getSuggestedMinimumHeight());
 
         setMeasuredDimension(
-                resolveSizeAndState(measuredWidth, widthSpec, 0),
+                resolveSizeAndState(measuredWidth,   widthSpec, 0),
                 resolveSizeAndState(measuredHeight, heightSpec, 0));
     }
 
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 7eddc9c..2184fd2 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -25,6 +25,7 @@
 import android.os.Debug;
 import android.os.Process;
 import android.os.SystemClock;
+import android.os.Trace;
 import android.util.EventLog;
 import android.util.Log;
 
@@ -528,6 +529,10 @@
             // Do an initial gc to clean up after startup
             gc();
 
+            // Disable tracing so that forked processes do not inherit stale tracing tags from
+            // Zygote.
+            Trace.setTracingEnabled(false);
+
             // If requested, start system server directly from Zygote
             if (argv.length != 2) {
                 throw new RuntimeException(argv[0] + USAGE_STRING);
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index dd57ef4..d26f79e 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -672,6 +672,9 @@
 
     private static class SmHandler extends Handler {
 
+        /** true if StateMachine has quit */
+        private boolean mHasQuit = false;
+
         /** The debug flag */
         private boolean mDbg = false;
 
@@ -773,29 +776,31 @@
          */
         @Override
         public final void handleMessage(Message msg) {
-            if (mDbg) mSm.log("handleMessage: E msg.what=" + msg.what);
+            if (!mHasQuit) {
+                if (mDbg) mSm.log("handleMessage: E msg.what=" + msg.what);
 
-            /** Save the current message */
-            mMsg = msg;
+                /** Save the current message */
+                mMsg = msg;
 
-            /** State that processed the message */
-            State msgProcessedState = null;
-            if (mIsConstructionCompleted) {
-                /** Normal path */
-                msgProcessedState = processMsg(msg);
-            } else if (!mIsConstructionCompleted && (mMsg.what == SM_INIT_CMD)
-                    && (mMsg.obj == mSmHandlerObj)) {
-                /** Initial one time path. */
-                mIsConstructionCompleted = true;
-                invokeEnterMethods(0);
-            } else {
-                throw new RuntimeException("StateMachine.handleMessage: "
-                        + "The start method not called, received msg: " + msg);
+                /** State that processed the message */
+                State msgProcessedState = null;
+                if (mIsConstructionCompleted) {
+                    /** Normal path */
+                    msgProcessedState = processMsg(msg);
+                } else if (!mIsConstructionCompleted && (mMsg.what == SM_INIT_CMD)
+                        && (mMsg.obj == mSmHandlerObj)) {
+                    /** Initial one time path. */
+                    mIsConstructionCompleted = true;
+                    invokeEnterMethods(0);
+                } else {
+                    throw new RuntimeException("StateMachine.handleMessage: "
+                            + "The start method not called, received msg: " + msg);
+                }
+                performTransitions(msgProcessedState, msg);
+
+                // We need to check if mSm == null here as we could be quitting.
+                if (mDbg && mSm != null) mSm.log("handleMessage: X");
             }
-            performTransitions(msgProcessedState, msg);
-
-            // We need to check if mSm == null here as we could be quitting.
-            if (mDbg && mSm != null) mSm.log("handleMessage: X");
         }
 
         /**
@@ -908,6 +913,7 @@
             mInitialState = null;
             mDestState = null;
             mDeferredMessages.clear();
+            mHasQuit = true;
         }
 
         /**
diff --git a/core/java/com/android/internal/widget/ScrollingTabContainerView.java b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
index 04931e7..fa29e6e1 100644
--- a/core/java/com/android/internal/widget/ScrollingTabContainerView.java
+++ b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
@@ -31,6 +31,8 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewParent;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.DecelerateInterpolator;
 import android.widget.AdapterView;
 import android.widget.BaseAdapter;
@@ -381,6 +383,29 @@
         }
 
         @Override
+        public void setSelected(boolean selected) {
+            final boolean changed = (isSelected() != selected);
+            super.setSelected(selected);
+            if (changed && selected) {
+                sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
+            }
+        }
+
+        @Override
+        public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+            super.onInitializeAccessibilityEvent(event);
+            // This view masquerades as an action bar tab.
+            event.setClassName(ActionBar.Tab.class.getName());
+        }
+
+        @Override
+        public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+            super.onInitializeAccessibilityNodeInfo(info);
+            // This view masquerades as an action bar tab.
+            info.setClassName(ActionBar.Tab.class.getName());
+        }
+
+        @Override
         public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 3e5586e..efb59ef 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -30,6 +30,7 @@
 	android_opengl_GLES11.cpp \
 	android_opengl_GLES11Ext.cpp \
 	android_opengl_GLES20.cpp \
+	android_opengl_GLES30.cpp \
 	android_database_CursorWindow.cpp \
 	android_database_SQLiteCommon.cpp \
 	android_database_SQLiteConnection.cpp \
diff --git a/core/jni/android_opengl_GLES30.cpp b/core/jni/android_opengl_GLES30.cpp
new file mode 100644
index 0000000..ac294bd
--- /dev/null
+++ b/core/jni/android_opengl_GLES30.cpp
@@ -0,0 +1,5217 @@
+/*
+**
+** Copyright 2013, 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.
+*/
+
+// This source file is automatically generated
+
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/misc.h>
+#include <assert.h>
+
+static int initialized = 0;
+
+static jclass nioAccessClass;
+static jclass bufferClass;
+static jmethodID getBasePointerID;
+static jmethodID getBaseArrayID;
+static jmethodID getBaseArrayOffsetID;
+static jfieldID positionID;
+static jfieldID limitID;
+static jfieldID elementSizeShiftID;
+
+
+/* special calls implemented in Android's GLES wrapper used to more
+ * efficiently bound-check passed arrays */
+extern "C" {
+#ifdef GL_VERSION_ES_CM_1_1
+GL_API void GL_APIENTRY glColorPointerBounds(GLint size, GLenum type, GLsizei stride,
+        const GLvoid *ptr, GLsizei count);
+GL_API void GL_APIENTRY glNormalPointerBounds(GLenum type, GLsizei stride,
+        const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glTexCoordPointerBounds(GLint size, GLenum type,
+        GLsizei stride, const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glVertexPointerBounds(GLint size, GLenum type,
+        GLsizei stride, const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glPointSizePointerOESBounds(GLenum type,
+        GLsizei stride, const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glMatrixIndexPointerOESBounds(GLint size, GLenum type,
+        GLsizei stride, const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type,
+        GLsizei stride, const GLvoid *pointer, GLsizei count);
+#endif
+#ifdef GL_ES_VERSION_2_0
+static void glVertexAttribPointerBounds(GLuint indx, GLint size, GLenum type,
+        GLboolean normalized, GLsizei stride, const GLvoid *pointer, GLsizei count) {
+    glVertexAttribPointer(indx, size, type, normalized, stride, pointer);
+}
+#endif
+#ifdef GL_ES_VERSION_3_0
+static void glVertexAttribIPointerBounds(GLuint indx, GLint size, GLenum type,
+        GLsizei stride, const GLvoid *pointer, GLsizei count) {
+    glVertexAttribIPointer(indx, size, type, stride, pointer);
+}
+#endif
+}
+
+/* Cache method IDs each time the class is loaded. */
+
+static void
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
+{
+    jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
+    nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
+
+    jclass bufferClassLocal = _env->FindClass("java/nio/Buffer");
+    bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal);
+
+    getBasePointerID = _env->GetStaticMethodID(nioAccessClass,
+            "getBasePointer", "(Ljava/nio/Buffer;)J");
+    getBaseArrayID = _env->GetStaticMethodID(nioAccessClass,
+            "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;");
+    getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass,
+            "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
+
+    positionID = _env->GetFieldID(bufferClass, "position", "I");
+    limitID = _env->GetFieldID(bufferClass, "limit", "I");
+    elementSizeShiftID =
+        _env->GetFieldID(bufferClass, "_elementSizeShift", "I");
+}
+
+static void *
+getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *offset)
+{
+    jint position;
+    jint limit;
+    jint elementSizeShift;
+    jlong pointer;
+
+    position = _env->GetIntField(buffer, positionID);
+    limit = _env->GetIntField(buffer, limitID);
+    elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
+    *remaining = (limit - position) << elementSizeShift;
+    pointer = _env->CallStaticLongMethod(nioAccessClass,
+            getBasePointerID, buffer);
+    if (pointer != 0L) {
+        *array = NULL;
+        return (void *) (jint) pointer;
+    }
+
+    *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
+            getBaseArrayID, buffer);
+    *offset = _env->CallStaticIntMethod(nioAccessClass,
+            getBaseArrayOffsetID, buffer);
+
+    return NULL;
+}
+
+static void
+releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit)
+{
+    _env->ReleasePrimitiveArrayCritical(array, data,
+                       commit ? 0 : JNI_ABORT);
+}
+
+static void *
+getDirectBufferPointer(JNIEnv *_env, jobject buffer) {
+    char* buf = (char*) _env->GetDirectBufferAddress(buffer);
+    if (buf) {
+        jint position = _env->GetIntField(buffer, positionID);
+        jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
+        buf += position << elementSizeShift;
+    } else {
+        jniThrowException(_env, "java/lang/IllegalArgumentException",
+                          "Must use a native order direct Buffer");
+    }
+    return (void*) buf;
+}
+
+// --------------------------------------------------------------------------
+
+/*
+ * returns the number of values glGet returns for a given pname.
+ *
+ * The code below is written such that pnames requiring only one values
+ * are the default (and are not explicitely tested for). This makes the
+ * checking code much shorter/readable/efficient.
+ *
+ * This means that unknown pnames (e.g.: extensions) will default to 1. If
+ * that unknown pname needs more than 1 value, then the validation check
+ * is incomplete and the app may crash if it passed the wrong number params.
+ */
+static int getNeededCount(GLint pname) {
+    int needed = 1;
+#ifdef GL_ES_VERSION_2_0
+    // GLES 2.x pnames
+    switch (pname) {
+        case GL_ALIASED_LINE_WIDTH_RANGE:
+        case GL_ALIASED_POINT_SIZE_RANGE:
+            needed = 2;
+            break;
+
+        case GL_BLEND_COLOR:
+        case GL_COLOR_CLEAR_VALUE:
+        case GL_COLOR_WRITEMASK:
+        case GL_SCISSOR_BOX:
+        case GL_VIEWPORT:
+            needed = 4;
+            break;
+
+        case GL_COMPRESSED_TEXTURE_FORMATS:
+            glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &needed);
+            break;
+
+        case GL_SHADER_BINARY_FORMATS:
+            glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &needed);
+            break;
+    }
+#endif
+
+#ifdef GL_VERSION_ES_CM_1_1
+    // GLES 1.x pnames
+    switch (pname) {
+        case GL_ALIASED_LINE_WIDTH_RANGE:
+        case GL_ALIASED_POINT_SIZE_RANGE:
+        case GL_DEPTH_RANGE:
+        case GL_SMOOTH_LINE_WIDTH_RANGE:
+        case GL_SMOOTH_POINT_SIZE_RANGE:
+            needed = 2;
+            break;
+
+        case GL_CURRENT_NORMAL:
+        case GL_POINT_DISTANCE_ATTENUATION:
+            needed = 3;
+            break;
+
+        case GL_COLOR_CLEAR_VALUE:
+        case GL_COLOR_WRITEMASK:
+        case GL_CURRENT_COLOR:
+        case GL_CURRENT_TEXTURE_COORDS:
+        case GL_FOG_COLOR:
+        case GL_LIGHT_MODEL_AMBIENT:
+        case GL_SCISSOR_BOX:
+        case GL_VIEWPORT:
+            needed = 4;
+            break;
+
+        case GL_MODELVIEW_MATRIX:
+        case GL_PROJECTION_MATRIX:
+        case GL_TEXTURE_MATRIX:
+            needed = 16;
+            break;
+
+        case GL_COMPRESSED_TEXTURE_FORMATS:
+            glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &needed);
+            break;
+    }
+#endif
+    return needed;
+}
+
+template <typename JTYPEARRAY, typename CTYPE, void GET(GLenum, CTYPE*)>
+static void
+get
+  (JNIEnv *_env, jobject _this, jint pname, JTYPEARRAY params_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType;
+    const char * _exceptionMessage;
+    CTYPE *params_base = (CTYPE *) 0;
+    jint _remaining;
+    CTYPE *params = (CTYPE *) 0;
+    int _needed = 0;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(params_ref) - offset;
+    _needed = getNeededCount(pname);
+    // if we didn't find this pname, we just assume the user passed
+    // an array of the right size -- this might happen with extensions
+    // or if we forget an enum here.
+    if (_remaining < _needed) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "length - offset < needed";
+        goto exit;
+    }
+    params_base = (CTYPE *)
+        _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+    params = params_base + offset;
+
+    GET(
+        (GLenum)pname,
+        (CTYPE *)params
+    );
+
+exit:
+    if (params_base) {
+        _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+
+template <typename CTYPE, void GET(GLenum, CTYPE*)>
+static void
+getarray
+  (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType;
+    const char * _exceptionMessage;
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    CTYPE *params = (CTYPE *) 0;
+    int _needed = 0;
+
+    params = (CTYPE *)getPointer(_env, params_buf, &_array, &_remaining, &_bufferOffset);
+    _needed = getNeededCount(pname);
+    // if we didn't find this pname, we just assume the user passed
+    // an array of the right size -- this might happen with extensions
+    // or if we forget an enum here.
+    if (_needed>0 && _remaining < _needed) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "remaining() < needed";
+        goto exit;
+    }
+    if (params == NULL) {
+        char * _paramsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        params = (CTYPE *) (_paramsBase + _bufferOffset);
+    }
+    GET(
+        (GLenum)pname,
+        (CTYPE *)params
+    );
+
+exit:
+    if (_array) {
+        releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+// --------------------------------------------------------------------------
+/* void glReadBuffer ( GLenum mode ) */
+static void
+android_glReadBuffer__I
+  (JNIEnv *_env, jobject _this, jint mode) {
+    glReadBuffer(
+        (GLenum)mode
+    );
+}
+
+/* void glDrawRangeElements ( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices ) */
+static void
+android_glDrawRangeElements__IIIIILjava_nio_Buffer_2
+  (JNIEnv *_env, jobject _this, jint mode, jint start, jint end, jint count, jint type, jobject indices_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLvoid *indices = (GLvoid *) 0;
+
+    indices = (GLvoid *)getPointer(_env, indices_buf, &_array, &_remaining, &_bufferOffset);
+    if (indices == NULL) {
+        char * _indicesBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        indices = (GLvoid *) (_indicesBase + _bufferOffset);
+    }
+    glDrawRangeElements(
+        (GLenum)mode,
+        (GLuint)start,
+        (GLuint)end,
+        (GLsizei)count,
+        (GLenum)type,
+        (GLvoid *)indices
+    );
+    if (_array) {
+        releasePointer(_env, _array, indices, JNI_FALSE);
+    }
+}
+
+/* void glDrawRangeElements ( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, GLsizei offset ) */
+static void
+android_glDrawRangeElements__IIIIII
+  (JNIEnv *_env, jobject _this, jint mode, jint start, jint end, jint count, jint type, jint offset) {
+    glDrawRangeElements(
+        (GLenum)mode,
+        (GLuint)start,
+        (GLuint)end,
+        (GLsizei)count,
+        (GLenum)type,
+        (GLvoid *)offset
+    );
+}
+
+/* void glTexImage3D ( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels ) */
+static void
+android_glTexImage3D__IIIIIIIIILjava_nio_Buffer_2
+  (JNIEnv *_env, jobject _this, jint target, jint level, jint internalformat, jint width, jint height, jint depth, jint border, jint format, jint type, jobject pixels_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLvoid *pixels = (GLvoid *) 0;
+
+    pixels = (GLvoid *)getPointer(_env, pixels_buf, &_array, &_remaining, &_bufferOffset);
+    if (pixels == NULL) {
+        char * _pixelsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        pixels = (GLvoid *) (_pixelsBase + _bufferOffset);
+    }
+    glTexImage3D(
+        (GLenum)target,
+        (GLint)level,
+        (GLint)internalformat,
+        (GLsizei)width,
+        (GLsizei)height,
+        (GLsizei)depth,
+        (GLint)border,
+        (GLenum)format,
+        (GLenum)type,
+        (GLvoid *)pixels
+    );
+    if (_array) {
+        releasePointer(_env, _array, pixels, JNI_FALSE);
+    }
+}
+
+/* void glTexImage3D ( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, GLsizei offset ) */
+static void
+android_glTexImage3D__IIIIIIIIII
+  (JNIEnv *_env, jobject _this, jint target, jint level, jint internalformat, jint width, jint height, jint depth, jint border, jint format, jint type, jint offset) {
+    glTexImage3D(
+        (GLenum)target,
+        (GLint)level,
+        (GLint)internalformat,
+        (GLsizei)width,
+        (GLsizei)height,
+        (GLsizei)depth,
+        (GLint)border,
+        (GLenum)format,
+        (GLenum)type,
+        (GLvoid *)offset
+    );
+}
+
+/* void glTexSubImage3D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels ) */
+static void
+android_glTexSubImage3D__IIIIIIIIIILjava_nio_Buffer_2
+  (JNIEnv *_env, jobject _this, jint target, jint level, jint xoffset, jint yoffset, jint zoffset, jint width, jint height, jint depth, jint format, jint type, jobject pixels_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLvoid *pixels = (GLvoid *) 0;
+
+    pixels = (GLvoid *)getPointer(_env, pixels_buf, &_array, &_remaining, &_bufferOffset);
+    if (pixels == NULL) {
+        char * _pixelsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        pixels = (GLvoid *) (_pixelsBase + _bufferOffset);
+    }
+    glTexSubImage3D(
+        (GLenum)target,
+        (GLint)level,
+        (GLint)xoffset,
+        (GLint)yoffset,
+        (GLint)zoffset,
+        (GLsizei)width,
+        (GLsizei)height,
+        (GLsizei)depth,
+        (GLenum)format,
+        (GLenum)type,
+        (GLvoid *)pixels
+    );
+    if (_array) {
+        releasePointer(_env, _array, pixels, JNI_FALSE);
+    }
+}
+
+/* void glTexSubImage3D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei offset ) */
+static void
+android_glTexSubImage3D__IIIIIIIIIII
+  (JNIEnv *_env, jobject _this, jint target, jint level, jint xoffset, jint yoffset, jint zoffset, jint width, jint height, jint depth, jint format, jint type, jint offset) {
+    glTexSubImage3D(
+        (GLenum)target,
+        (GLint)level,
+        (GLint)xoffset,
+        (GLint)yoffset,
+        (GLint)zoffset,
+        (GLsizei)width,
+        (GLsizei)height,
+        (GLsizei)depth,
+        (GLenum)format,
+        (GLenum)type,
+        (GLvoid *)offset
+    );
+}
+
+/* void glCopyTexSubImage3D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height ) */
+static void
+android_glCopyTexSubImage3D__IIIIIIIII
+  (JNIEnv *_env, jobject _this, jint target, jint level, jint xoffset, jint yoffset, jint zoffset, jint x, jint y, jint width, jint height) {
+    glCopyTexSubImage3D(
+        (GLenum)target,
+        (GLint)level,
+        (GLint)xoffset,
+        (GLint)yoffset,
+        (GLint)zoffset,
+        (GLint)x,
+        (GLint)y,
+        (GLsizei)width,
+        (GLsizei)height
+    );
+}
+
+/* void glCompressedTexImage3D ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data ) */
+static void
+android_glCompressedTexImage3D__IIIIIIIILjava_nio_Buffer_2
+  (JNIEnv *_env, jobject _this, jint target, jint level, jint internalformat, jint width, jint height, jint depth, jint border, jint imageSize, jobject data_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLvoid *data = (GLvoid *) 0;
+
+    data = (GLvoid *)getPointer(_env, data_buf, &_array, &_remaining, &_bufferOffset);
+    if (data == NULL) {
+        char * _dataBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        data = (GLvoid *) (_dataBase + _bufferOffset);
+    }
+    glCompressedTexImage3D(
+        (GLenum)target,
+        (GLint)level,
+        (GLenum)internalformat,
+        (GLsizei)width,
+        (GLsizei)height,
+        (GLsizei)depth,
+        (GLint)border,
+        (GLsizei)imageSize,
+        (GLvoid *)data
+    );
+    if (_array) {
+        releasePointer(_env, _array, data, JNI_FALSE);
+    }
+}
+
+/* void glCompressedTexImage3D ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, GLsizei offset ) */
+static void
+android_glCompressedTexImage3D__IIIIIIIII
+  (JNIEnv *_env, jobject _this, jint target, jint level, jint internalformat, jint width, jint height, jint depth, jint border, jint imageSize, jint offset) {
+    glCompressedTexImage3D(
+        (GLenum)target,
+        (GLint)level,
+        (GLenum)internalformat,
+        (GLsizei)width,
+        (GLsizei)height,
+        (GLsizei)depth,
+        (GLint)border,
+        (GLsizei)imageSize,
+        (GLvoid *)offset
+    );
+}
+
+/* void glCompressedTexSubImage3D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data ) */
+static void
+android_glCompressedTexSubImage3D__IIIIIIIIIILjava_nio_Buffer_2
+  (JNIEnv *_env, jobject _this, jint target, jint level, jint xoffset, jint yoffset, jint zoffset, jint width, jint height, jint depth, jint format, jint imageSize, jobject data_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLvoid *data = (GLvoid *) 0;
+
+    data = (GLvoid *)getPointer(_env, data_buf, &_array, &_remaining, &_bufferOffset);
+    if (data == NULL) {
+        char * _dataBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        data = (GLvoid *) (_dataBase + _bufferOffset);
+    }
+    glCompressedTexSubImage3D(
+        (GLenum)target,
+        (GLint)level,
+        (GLint)xoffset,
+        (GLint)yoffset,
+        (GLint)zoffset,
+        (GLsizei)width,
+        (GLsizei)height,
+        (GLsizei)depth,
+        (GLenum)format,
+        (GLsizei)imageSize,
+        (GLvoid *)data
+    );
+    if (_array) {
+        releasePointer(_env, _array, data, JNI_FALSE);
+    }
+}
+
+/* void glCompressedTexSubImage3D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, GLsizei offset ) */
+static void
+android_glCompressedTexSubImage3D__IIIIIIIIIII
+  (JNIEnv *_env, jobject _this, jint target, jint level, jint xoffset, jint yoffset, jint zoffset, jint width, jint height, jint depth, jint format, jint imageSize, jint offset) {
+    glCompressedTexSubImage3D(
+        (GLenum)target,
+        (GLint)level,
+        (GLint)xoffset,
+        (GLint)yoffset,
+        (GLint)zoffset,
+        (GLsizei)width,
+        (GLsizei)height,
+        (GLsizei)depth,
+        (GLenum)format,
+        (GLsizei)imageSize,
+        (GLvoid *)offset
+    );
+}
+
+/* void glGenQueries ( GLsizei n, GLuint *ids ) */
+static void
+android_glGenQueries__I_3II
+  (JNIEnv *_env, jobject _this, jint n, jintArray ids_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *ids_base = (GLuint *) 0;
+    jint _remaining;
+    GLuint *ids = (GLuint *) 0;
+
+    if (!ids_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "ids == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(ids_ref) - offset;
+    ids_base = (GLuint *)
+        _env->GetPrimitiveArrayCritical(ids_ref, (jboolean *)0);
+    ids = ids_base + offset;
+
+    glGenQueries(
+        (GLsizei)n,
+        (GLuint *)ids
+    );
+
+exit:
+    if (ids_base) {
+        _env->ReleasePrimitiveArrayCritical(ids_ref, ids_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGenQueries ( GLsizei n, GLuint *ids ) */
+static void
+android_glGenQueries__ILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint n, jobject ids_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLuint *ids = (GLuint *) 0;
+
+    ids = (GLuint *)getPointer(_env, ids_buf, &_array, &_remaining, &_bufferOffset);
+    if (ids == NULL) {
+        char * _idsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        ids = (GLuint *) (_idsBase + _bufferOffset);
+    }
+    glGenQueries(
+        (GLsizei)n,
+        (GLuint *)ids
+    );
+    if (_array) {
+        releasePointer(_env, _array, ids, JNI_TRUE);
+    }
+}
+
+/* void glDeleteQueries ( GLsizei n, const GLuint *ids ) */
+static void
+android_glDeleteQueries__I_3II
+  (JNIEnv *_env, jobject _this, jint n, jintArray ids_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *ids_base = (GLuint *) 0;
+    jint _remaining;
+    GLuint *ids = (GLuint *) 0;
+
+    if (!ids_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "ids == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(ids_ref) - offset;
+    ids_base = (GLuint *)
+        _env->GetPrimitiveArrayCritical(ids_ref, (jboolean *)0);
+    ids = ids_base + offset;
+
+    glDeleteQueries(
+        (GLsizei)n,
+        (GLuint *)ids
+    );
+
+exit:
+    if (ids_base) {
+        _env->ReleasePrimitiveArrayCritical(ids_ref, ids_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glDeleteQueries ( GLsizei n, const GLuint *ids ) */
+static void
+android_glDeleteQueries__ILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint n, jobject ids_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLuint *ids = (GLuint *) 0;
+
+    ids = (GLuint *)getPointer(_env, ids_buf, &_array, &_remaining, &_bufferOffset);
+    if (ids == NULL) {
+        char * _idsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        ids = (GLuint *) (_idsBase + _bufferOffset);
+    }
+    glDeleteQueries(
+        (GLsizei)n,
+        (GLuint *)ids
+    );
+    if (_array) {
+        releasePointer(_env, _array, ids, JNI_FALSE);
+    }
+}
+
+/* GLboolean glIsQuery ( GLuint id ) */
+static jboolean
+android_glIsQuery__I
+  (JNIEnv *_env, jobject _this, jint id) {
+    GLboolean _returnValue;
+    _returnValue = glIsQuery(
+        (GLuint)id
+    );
+    return (jboolean)_returnValue;
+}
+
+/* void glBeginQuery ( GLenum target, GLuint id ) */
+static void
+android_glBeginQuery__II
+  (JNIEnv *_env, jobject _this, jint target, jint id) {
+    glBeginQuery(
+        (GLenum)target,
+        (GLuint)id
+    );
+}
+
+/* void glEndQuery ( GLenum target ) */
+static void
+android_glEndQuery__I
+  (JNIEnv *_env, jobject _this, jint target) {
+    glEndQuery(
+        (GLenum)target
+    );
+}
+
+/* void glGetQueryiv ( GLenum target, GLenum pname, GLint *params ) */
+static void
+android_glGetQueryiv__II_3II
+  (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLint *params_base = (GLint *) 0;
+    jint _remaining;
+    GLint *params = (GLint *) 0;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(params_ref) - offset;
+    params_base = (GLint *)
+        _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+    params = params_base + offset;
+
+    glGetQueryiv(
+        (GLenum)target,
+        (GLenum)pname,
+        (GLint *)params
+    );
+
+exit:
+    if (params_base) {
+        _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetQueryiv ( GLenum target, GLenum pname, GLint *params ) */
+static void
+android_glGetQueryiv__IILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLint *params = (GLint *) 0;
+
+    params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining, &_bufferOffset);
+    if (params == NULL) {
+        char * _paramsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        params = (GLint *) (_paramsBase + _bufferOffset);
+    }
+    glGetQueryiv(
+        (GLenum)target,
+        (GLenum)pname,
+        (GLint *)params
+    );
+    if (_array) {
+        releasePointer(_env, _array, params, JNI_TRUE);
+    }
+}
+
+/* void glGetQueryObjectuiv ( GLuint id, GLenum pname, GLuint *params ) */
+static void
+android_glGetQueryObjectuiv__II_3II
+  (JNIEnv *_env, jobject _this, jint id, jint pname, jintArray params_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *params_base = (GLuint *) 0;
+    jint _remaining;
+    GLuint *params = (GLuint *) 0;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(params_ref) - offset;
+    params_base = (GLuint *)
+        _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+    params = params_base + offset;
+
+    glGetQueryObjectuiv(
+        (GLuint)id,
+        (GLenum)pname,
+        (GLuint *)params
+    );
+
+exit:
+    if (params_base) {
+        _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetQueryObjectuiv ( GLuint id, GLenum pname, GLuint *params ) */
+static void
+android_glGetQueryObjectuiv__IILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint id, jint pname, jobject params_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLuint *params = (GLuint *) 0;
+
+    params = (GLuint *)getPointer(_env, params_buf, &_array, &_remaining, &_bufferOffset);
+    if (params == NULL) {
+        char * _paramsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        params = (GLuint *) (_paramsBase + _bufferOffset);
+    }
+    glGetQueryObjectuiv(
+        (GLuint)id,
+        (GLenum)pname,
+        (GLuint *)params
+    );
+    if (_array) {
+        releasePointer(_env, _array, params, JNI_TRUE);
+    }
+}
+
+/* GLboolean glUnmapBuffer ( GLenum target ) */
+static jboolean
+android_glUnmapBuffer__I
+  (JNIEnv *_env, jobject _this, jint target) {
+    GLboolean _returnValue;
+    _returnValue = glUnmapBuffer(
+        (GLenum)target
+    );
+    return (jboolean)_returnValue;
+}
+
+/* void glGetBufferPointerv ( GLenum target, GLenum pname, GLvoid** params ) */
+static jobject
+android_glGetBufferPointerv__II
+  (JNIEnv *_env, jobject _this, jint target, jint pname) {
+    GLint64 _mapLength;
+    GLvoid* _p;
+    glGetBufferParameteri64v((GLenum)target, GL_BUFFER_MAP_LENGTH, &_mapLength);
+    glGetBufferPointerv((GLenum)target, (GLenum)pname, &_p);
+    return _env->NewDirectByteBuffer(_p, _mapLength);
+}
+
+/* void glDrawBuffers ( GLsizei n, const GLenum *bufs ) */
+static void
+android_glDrawBuffers__I_3II
+  (JNIEnv *_env, jobject _this, jint n, jintArray bufs_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLenum *bufs_base = (GLenum *) 0;
+    jint _remaining;
+    GLenum *bufs = (GLenum *) 0;
+
+    if (!bufs_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "bufs == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(bufs_ref) - offset;
+    bufs_base = (GLenum *)
+        _env->GetPrimitiveArrayCritical(bufs_ref, (jboolean *)0);
+    bufs = bufs_base + offset;
+
+    glDrawBuffers(
+        (GLsizei)n,
+        (GLenum *)bufs
+    );
+
+exit:
+    if (bufs_base) {
+        _env->ReleasePrimitiveArrayCritical(bufs_ref, bufs_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glDrawBuffers ( GLsizei n, const GLenum *bufs ) */
+static void
+android_glDrawBuffers__ILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint n, jobject bufs_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLenum *bufs = (GLenum *) 0;
+
+    bufs = (GLenum *)getPointer(_env, bufs_buf, &_array, &_remaining, &_bufferOffset);
+    if (bufs == NULL) {
+        char * _bufsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        bufs = (GLenum *) (_bufsBase + _bufferOffset);
+    }
+    glDrawBuffers(
+        (GLsizei)n,
+        (GLenum *)bufs
+    );
+    if (_array) {
+        releasePointer(_env, _array, bufs, JNI_FALSE);
+    }
+}
+
+/* void glUniformMatrix2x3fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) */
+static void
+android_glUniformMatrix2x3fv__IIZ_3FI
+  (JNIEnv *_env, jobject _this, jint location, jint count, jboolean transpose, jfloatArray value_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLfloat *value_base = (GLfloat *) 0;
+    jint _remaining;
+    GLfloat *value = (GLfloat *) 0;
+
+    if (!value_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(value_ref) - offset;
+    value_base = (GLfloat *)
+        _env->GetPrimitiveArrayCritical(value_ref, (jboolean *)0);
+    value = value_base + offset;
+
+    glUniformMatrix2x3fv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLboolean)transpose,
+        (GLfloat *)value
+    );
+
+exit:
+    if (value_base) {
+        _env->ReleasePrimitiveArrayCritical(value_ref, value_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glUniformMatrix2x3fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) */
+static void
+android_glUniformMatrix2x3fv__IIZLjava_nio_FloatBuffer_2
+  (JNIEnv *_env, jobject _this, jint location, jint count, jboolean transpose, jobject value_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLfloat *value = (GLfloat *) 0;
+
+    value = (GLfloat *)getPointer(_env, value_buf, &_array, &_remaining, &_bufferOffset);
+    if (value == NULL) {
+        char * _valueBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        value = (GLfloat *) (_valueBase + _bufferOffset);
+    }
+    glUniformMatrix2x3fv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLboolean)transpose,
+        (GLfloat *)value
+    );
+    if (_array) {
+        releasePointer(_env, _array, value, JNI_FALSE);
+    }
+}
+
+/* void glUniformMatrix3x2fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) */
+static void
+android_glUniformMatrix3x2fv__IIZ_3FI
+  (JNIEnv *_env, jobject _this, jint location, jint count, jboolean transpose, jfloatArray value_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLfloat *value_base = (GLfloat *) 0;
+    jint _remaining;
+    GLfloat *value = (GLfloat *) 0;
+
+    if (!value_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(value_ref) - offset;
+    value_base = (GLfloat *)
+        _env->GetPrimitiveArrayCritical(value_ref, (jboolean *)0);
+    value = value_base + offset;
+
+    glUniformMatrix3x2fv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLboolean)transpose,
+        (GLfloat *)value
+    );
+
+exit:
+    if (value_base) {
+        _env->ReleasePrimitiveArrayCritical(value_ref, value_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glUniformMatrix3x2fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) */
+static void
+android_glUniformMatrix3x2fv__IIZLjava_nio_FloatBuffer_2
+  (JNIEnv *_env, jobject _this, jint location, jint count, jboolean transpose, jobject value_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLfloat *value = (GLfloat *) 0;
+
+    value = (GLfloat *)getPointer(_env, value_buf, &_array, &_remaining, &_bufferOffset);
+    if (value == NULL) {
+        char * _valueBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        value = (GLfloat *) (_valueBase + _bufferOffset);
+    }
+    glUniformMatrix3x2fv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLboolean)transpose,
+        (GLfloat *)value
+    );
+    if (_array) {
+        releasePointer(_env, _array, value, JNI_FALSE);
+    }
+}
+
+/* void glUniformMatrix2x4fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) */
+static void
+android_glUniformMatrix2x4fv__IIZ_3FI
+  (JNIEnv *_env, jobject _this, jint location, jint count, jboolean transpose, jfloatArray value_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLfloat *value_base = (GLfloat *) 0;
+    jint _remaining;
+    GLfloat *value = (GLfloat *) 0;
+
+    if (!value_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(value_ref) - offset;
+    value_base = (GLfloat *)
+        _env->GetPrimitiveArrayCritical(value_ref, (jboolean *)0);
+    value = value_base + offset;
+
+    glUniformMatrix2x4fv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLboolean)transpose,
+        (GLfloat *)value
+    );
+
+exit:
+    if (value_base) {
+        _env->ReleasePrimitiveArrayCritical(value_ref, value_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glUniformMatrix2x4fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) */
+static void
+android_glUniformMatrix2x4fv__IIZLjava_nio_FloatBuffer_2
+  (JNIEnv *_env, jobject _this, jint location, jint count, jboolean transpose, jobject value_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLfloat *value = (GLfloat *) 0;
+
+    value = (GLfloat *)getPointer(_env, value_buf, &_array, &_remaining, &_bufferOffset);
+    if (value == NULL) {
+        char * _valueBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        value = (GLfloat *) (_valueBase + _bufferOffset);
+    }
+    glUniformMatrix2x4fv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLboolean)transpose,
+        (GLfloat *)value
+    );
+    if (_array) {
+        releasePointer(_env, _array, value, JNI_FALSE);
+    }
+}
+
+/* void glUniformMatrix4x2fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) */
+static void
+android_glUniformMatrix4x2fv__IIZ_3FI
+  (JNIEnv *_env, jobject _this, jint location, jint count, jboolean transpose, jfloatArray value_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLfloat *value_base = (GLfloat *) 0;
+    jint _remaining;
+    GLfloat *value = (GLfloat *) 0;
+
+    if (!value_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(value_ref) - offset;
+    value_base = (GLfloat *)
+        _env->GetPrimitiveArrayCritical(value_ref, (jboolean *)0);
+    value = value_base + offset;
+
+    glUniformMatrix4x2fv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLboolean)transpose,
+        (GLfloat *)value
+    );
+
+exit:
+    if (value_base) {
+        _env->ReleasePrimitiveArrayCritical(value_ref, value_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glUniformMatrix4x2fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) */
+static void
+android_glUniformMatrix4x2fv__IIZLjava_nio_FloatBuffer_2
+  (JNIEnv *_env, jobject _this, jint location, jint count, jboolean transpose, jobject value_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLfloat *value = (GLfloat *) 0;
+
+    value = (GLfloat *)getPointer(_env, value_buf, &_array, &_remaining, &_bufferOffset);
+    if (value == NULL) {
+        char * _valueBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        value = (GLfloat *) (_valueBase + _bufferOffset);
+    }
+    glUniformMatrix4x2fv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLboolean)transpose,
+        (GLfloat *)value
+    );
+    if (_array) {
+        releasePointer(_env, _array, value, JNI_FALSE);
+    }
+}
+
+/* void glUniformMatrix3x4fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) */
+static void
+android_glUniformMatrix3x4fv__IIZ_3FI
+  (JNIEnv *_env, jobject _this, jint location, jint count, jboolean transpose, jfloatArray value_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLfloat *value_base = (GLfloat *) 0;
+    jint _remaining;
+    GLfloat *value = (GLfloat *) 0;
+
+    if (!value_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(value_ref) - offset;
+    value_base = (GLfloat *)
+        _env->GetPrimitiveArrayCritical(value_ref, (jboolean *)0);
+    value = value_base + offset;
+
+    glUniformMatrix3x4fv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLboolean)transpose,
+        (GLfloat *)value
+    );
+
+exit:
+    if (value_base) {
+        _env->ReleasePrimitiveArrayCritical(value_ref, value_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glUniformMatrix3x4fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) */
+static void
+android_glUniformMatrix3x4fv__IIZLjava_nio_FloatBuffer_2
+  (JNIEnv *_env, jobject _this, jint location, jint count, jboolean transpose, jobject value_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLfloat *value = (GLfloat *) 0;
+
+    value = (GLfloat *)getPointer(_env, value_buf, &_array, &_remaining, &_bufferOffset);
+    if (value == NULL) {
+        char * _valueBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        value = (GLfloat *) (_valueBase + _bufferOffset);
+    }
+    glUniformMatrix3x4fv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLboolean)transpose,
+        (GLfloat *)value
+    );
+    if (_array) {
+        releasePointer(_env, _array, value, JNI_FALSE);
+    }
+}
+
+/* void glUniformMatrix4x3fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) */
+static void
+android_glUniformMatrix4x3fv__IIZ_3FI
+  (JNIEnv *_env, jobject _this, jint location, jint count, jboolean transpose, jfloatArray value_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLfloat *value_base = (GLfloat *) 0;
+    jint _remaining;
+    GLfloat *value = (GLfloat *) 0;
+
+    if (!value_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(value_ref) - offset;
+    value_base = (GLfloat *)
+        _env->GetPrimitiveArrayCritical(value_ref, (jboolean *)0);
+    value = value_base + offset;
+
+    glUniformMatrix4x3fv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLboolean)transpose,
+        (GLfloat *)value
+    );
+
+exit:
+    if (value_base) {
+        _env->ReleasePrimitiveArrayCritical(value_ref, value_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glUniformMatrix4x3fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) */
+static void
+android_glUniformMatrix4x3fv__IIZLjava_nio_FloatBuffer_2
+  (JNIEnv *_env, jobject _this, jint location, jint count, jboolean transpose, jobject value_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLfloat *value = (GLfloat *) 0;
+
+    value = (GLfloat *)getPointer(_env, value_buf, &_array, &_remaining, &_bufferOffset);
+    if (value == NULL) {
+        char * _valueBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        value = (GLfloat *) (_valueBase + _bufferOffset);
+    }
+    glUniformMatrix4x3fv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLboolean)transpose,
+        (GLfloat *)value
+    );
+    if (_array) {
+        releasePointer(_env, _array, value, JNI_FALSE);
+    }
+}
+
+/* void glBlitFramebuffer ( GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter ) */
+static void
+android_glBlitFramebuffer__IIIIIIIIII
+  (JNIEnv *_env, jobject _this, jint srcX0, jint srcY0, jint srcX1, jint srcY1, jint dstX0, jint dstY0, jint dstX1, jint dstY1, jint mask, jint filter) {
+    glBlitFramebuffer(
+        (GLint)srcX0,
+        (GLint)srcY0,
+        (GLint)srcX1,
+        (GLint)srcY1,
+        (GLint)dstX0,
+        (GLint)dstY0,
+        (GLint)dstX1,
+        (GLint)dstY1,
+        (GLbitfield)mask,
+        (GLenum)filter
+    );
+}
+
+/* void glRenderbufferStorageMultisample ( GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height ) */
+static void
+android_glRenderbufferStorageMultisample__IIIII
+  (JNIEnv *_env, jobject _this, jint target, jint samples, jint internalformat, jint width, jint height) {
+    glRenderbufferStorageMultisample(
+        (GLenum)target,
+        (GLsizei)samples,
+        (GLenum)internalformat,
+        (GLsizei)width,
+        (GLsizei)height
+    );
+}
+
+/* void glFramebufferTextureLayer ( GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer ) */
+static void
+android_glFramebufferTextureLayer__IIIII
+  (JNIEnv *_env, jobject _this, jint target, jint attachment, jint texture, jint level, jint layer) {
+    glFramebufferTextureLayer(
+        (GLenum)target,
+        (GLenum)attachment,
+        (GLuint)texture,
+        (GLint)level,
+        (GLint)layer
+    );
+}
+
+/* GLvoid * glMapBufferRange ( GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access ) */
+static jobject
+android_glMapBufferRange__IIII
+  (JNIEnv *_env, jobject _this, jint target, jint offset, jint length, jint access) {
+    GLvoid* _p = glMapBufferRange((GLenum)target,
+            (GLintptr)offset, (GLsizeiptr)length, (GLbitfield)access);
+    jobject _buf = (jobject)0;
+    if (_p) {
+        _buf = _env->NewDirectByteBuffer(_p, length);
+    }
+    return _buf;
+}
+
+/* void glFlushMappedBufferRange ( GLenum target, GLintptr offset, GLsizeiptr length ) */
+static void
+android_glFlushMappedBufferRange__III
+  (JNIEnv *_env, jobject _this, jint target, jint offset, jint length) {
+    glFlushMappedBufferRange(
+        (GLenum)target,
+        (GLintptr)offset,
+        (GLsizeiptr)length
+    );
+}
+
+/* void glBindVertexArray ( GLuint array ) */
+static void
+android_glBindVertexArray__I
+  (JNIEnv *_env, jobject _this, jint array) {
+    glBindVertexArray(
+        (GLuint)array
+    );
+}
+
+/* void glDeleteVertexArrays ( GLsizei n, const GLuint *arrays ) */
+static void
+android_glDeleteVertexArrays__I_3II
+  (JNIEnv *_env, jobject _this, jint n, jintArray arrays_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *arrays_base = (GLuint *) 0;
+    jint _remaining;
+    GLuint *arrays = (GLuint *) 0;
+
+    if (!arrays_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "arrays == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(arrays_ref) - offset;
+    arrays_base = (GLuint *)
+        _env->GetPrimitiveArrayCritical(arrays_ref, (jboolean *)0);
+    arrays = arrays_base + offset;
+
+    glDeleteVertexArrays(
+        (GLsizei)n,
+        (GLuint *)arrays
+    );
+
+exit:
+    if (arrays_base) {
+        _env->ReleasePrimitiveArrayCritical(arrays_ref, arrays_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glDeleteVertexArrays ( GLsizei n, const GLuint *arrays ) */
+static void
+android_glDeleteVertexArrays__ILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint n, jobject arrays_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLuint *arrays = (GLuint *) 0;
+
+    arrays = (GLuint *)getPointer(_env, arrays_buf, &_array, &_remaining, &_bufferOffset);
+    if (arrays == NULL) {
+        char * _arraysBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        arrays = (GLuint *) (_arraysBase + _bufferOffset);
+    }
+    glDeleteVertexArrays(
+        (GLsizei)n,
+        (GLuint *)arrays
+    );
+    if (_array) {
+        releasePointer(_env, _array, arrays, JNI_FALSE);
+    }
+}
+
+/* void glGenVertexArrays ( GLsizei n, GLuint *arrays ) */
+static void
+android_glGenVertexArrays__I_3II
+  (JNIEnv *_env, jobject _this, jint n, jintArray arrays_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *arrays_base = (GLuint *) 0;
+    jint _remaining;
+    GLuint *arrays = (GLuint *) 0;
+
+    if (!arrays_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "arrays == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(arrays_ref) - offset;
+    arrays_base = (GLuint *)
+        _env->GetPrimitiveArrayCritical(arrays_ref, (jboolean *)0);
+    arrays = arrays_base + offset;
+
+    glGenVertexArrays(
+        (GLsizei)n,
+        (GLuint *)arrays
+    );
+
+exit:
+    if (arrays_base) {
+        _env->ReleasePrimitiveArrayCritical(arrays_ref, arrays_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGenVertexArrays ( GLsizei n, GLuint *arrays ) */
+static void
+android_glGenVertexArrays__ILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint n, jobject arrays_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLuint *arrays = (GLuint *) 0;
+
+    arrays = (GLuint *)getPointer(_env, arrays_buf, &_array, &_remaining, &_bufferOffset);
+    if (arrays == NULL) {
+        char * _arraysBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        arrays = (GLuint *) (_arraysBase + _bufferOffset);
+    }
+    glGenVertexArrays(
+        (GLsizei)n,
+        (GLuint *)arrays
+    );
+    if (_array) {
+        releasePointer(_env, _array, arrays, JNI_TRUE);
+    }
+}
+
+/* GLboolean glIsVertexArray ( GLuint array ) */
+static jboolean
+android_glIsVertexArray__I
+  (JNIEnv *_env, jobject _this, jint array) {
+    GLboolean _returnValue;
+    _returnValue = glIsVertexArray(
+        (GLuint)array
+    );
+    return (jboolean)_returnValue;
+}
+
+/* void glGetIntegeri_v ( GLenum target, GLuint index, GLint *data ) */
+static void
+android_glGetIntegeri_v__II_3II
+  (JNIEnv *_env, jobject _this, jint target, jint index, jintArray data_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLint *data_base = (GLint *) 0;
+    jint _remaining;
+    GLint *data = (GLint *) 0;
+
+    if (!data_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "data == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(data_ref) - offset;
+    data_base = (GLint *)
+        _env->GetPrimitiveArrayCritical(data_ref, (jboolean *)0);
+    data = data_base + offset;
+
+    glGetIntegeri_v(
+        (GLenum)target,
+        (GLuint)index,
+        (GLint *)data
+    );
+
+exit:
+    if (data_base) {
+        _env->ReleasePrimitiveArrayCritical(data_ref, data_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetIntegeri_v ( GLenum target, GLuint index, GLint *data ) */
+static void
+android_glGetIntegeri_v__IILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint target, jint index, jobject data_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLint *data = (GLint *) 0;
+
+    data = (GLint *)getPointer(_env, data_buf, &_array, &_remaining, &_bufferOffset);
+    if (data == NULL) {
+        char * _dataBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        data = (GLint *) (_dataBase + _bufferOffset);
+    }
+    glGetIntegeri_v(
+        (GLenum)target,
+        (GLuint)index,
+        (GLint *)data
+    );
+    if (_array) {
+        releasePointer(_env, _array, data, JNI_TRUE);
+    }
+}
+
+/* void glBeginTransformFeedback ( GLenum primitiveMode ) */
+static void
+android_glBeginTransformFeedback__I
+  (JNIEnv *_env, jobject _this, jint primitiveMode) {
+    glBeginTransformFeedback(
+        (GLenum)primitiveMode
+    );
+}
+
+/* void glEndTransformFeedback ( void ) */
+static void
+android_glEndTransformFeedback__
+  (JNIEnv *_env, jobject _this) {
+    glEndTransformFeedback();
+}
+
+/* void glBindBufferRange ( GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size ) */
+static void
+android_glBindBufferRange__IIIII
+  (JNIEnv *_env, jobject _this, jint target, jint index, jint buffer, jint offset, jint size) {
+    glBindBufferRange(
+        (GLenum)target,
+        (GLuint)index,
+        (GLuint)buffer,
+        (GLintptr)offset,
+        (GLsizeiptr)size
+    );
+}
+
+/* void glBindBufferBase ( GLenum target, GLuint index, GLuint buffer ) */
+static void
+android_glBindBufferBase__III
+  (JNIEnv *_env, jobject _this, jint target, jint index, jint buffer) {
+    glBindBufferBase(
+        (GLenum)target,
+        (GLuint)index,
+        (GLuint)buffer
+    );
+}
+
+/* void glTransformFeedbackVaryings ( GLuint program, GLsizei count, const GLchar *varyings, GLenum bufferMode ) */
+static
+void
+android_glTransformFeedbackVaryings
+    (JNIEnv *_env, jobject _this, jint program, jobjectArray varyings_ref, jint bufferMode) {
+    jint _exception = 0;
+    const char* _exceptionType = NULL;
+    const char* _exceptionMessage = NULL;
+    jint _count = 0, _i;
+    const char** _varyings = NULL;
+    const char* _varying = NULL;
+
+    if (!varyings_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "varyings == null";
+        goto exit;
+    }
+
+    _count = _env->GetArrayLength(varyings_ref);
+    _varyings = (const char**)calloc(_count, sizeof(const char*));
+    for (_i = 0; _i < _count; _i++) {
+        jstring _varying = (jstring)_env->GetObjectArrayElement(varyings_ref, _i);
+        if (!_varying) {
+            _exception = 1;
+            _exceptionType = "java/lang/IllegalArgumentException";
+            _exceptionMessage = "null varyings element";
+            goto exit;
+        }
+        _varyings[_i] = _env->GetStringUTFChars(_varying, 0);
+    }
+
+    glTransformFeedbackVaryings(program, _count, _varyings, bufferMode);
+
+exit:
+    for (_i = _count - 1; _i >= 0; _i--) {
+        if (_varyings[_i]) {
+            jstring _varying = (jstring)_env->GetObjectArrayElement(varyings_ref, _i);
+            if (_varying) {
+                _env->ReleaseStringUTFChars(_varying, _varyings[_i]);
+            }
+        }
+    }
+    free(_varyings);
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name ) */
+static void
+android_glGetTransformFeedbackVarying__III_3II_3II_3II_3BI
+  (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jintArray length_ref, jint lengthOffset, jintArray size_ref, jint sizeOffset, jintArray type_ref, jint typeOffset, jbyteArray name_ref, jint nameOffset) {
+    jint _exception = 0;
+    const char * _exceptionType;
+    const char * _exceptionMessage;
+    GLsizei *length_base = (GLsizei *) 0;
+    jint _lengthRemaining;
+    GLsizei *length = (GLsizei *) 0;
+    GLint *size_base = (GLint *) 0;
+    jint _sizeRemaining;
+    GLint *size = (GLint *) 0;
+    GLenum *type_base = (GLenum *) 0;
+    jint _typeRemaining;
+    GLenum *type = (GLenum *) 0;
+    char *name_base = (char *) 0;
+    jint _nameRemaining;
+    char *name = (char *) 0;
+
+    if (!length_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "length == null";
+        goto exit;
+    }
+    if (lengthOffset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "lengthOffset < 0";
+        goto exit;
+    }
+    _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset;
+    length_base = (GLsizei *)
+        _env->GetPrimitiveArrayCritical(length_ref, (jboolean *)0);
+    length = length_base + lengthOffset;
+
+    if (!size_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "size == null";
+        goto exit;
+    }
+    if (sizeOffset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "sizeOffset < 0";
+        goto exit;
+    }
+    _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset;
+    size_base = (GLint *)
+        _env->GetPrimitiveArrayCritical(size_ref, (jboolean *)0);
+    size = size_base + sizeOffset;
+
+    if (!type_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "type == null";
+        goto exit;
+    }
+    if (typeOffset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "typeOffset < 0";
+        goto exit;
+    }
+    _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset;
+    type_base = (GLenum *)
+        _env->GetPrimitiveArrayCritical(type_ref, (jboolean *)0);
+    type = type_base + typeOffset;
+
+    if (!name_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "name == null";
+        goto exit;
+    }
+    if (nameOffset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "nameOffset < 0";
+        goto exit;
+    }
+    _nameRemaining = _env->GetArrayLength(name_ref) - nameOffset;
+    name_base = (char *)
+        _env->GetPrimitiveArrayCritical(name_ref, (jboolean *)0);
+    name = name_base + nameOffset;
+
+    glGetTransformFeedbackVarying(
+        (GLuint)program,
+        (GLuint)index,
+        (GLsizei)bufsize,
+        (GLsizei *)length,
+        (GLint *)size,
+        (GLenum *)type,
+        (char *)name
+    );
+
+exit:
+    if (name_base) {
+        _env->ReleasePrimitiveArrayCritical(name_ref, name_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (type_base) {
+        _env->ReleasePrimitiveArrayCritical(type_ref, type_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (size_base) {
+        _env->ReleasePrimitiveArrayCritical(size_ref, size_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (length_base) {
+        _env->ReleasePrimitiveArrayCritical(length_ref, length_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name ) */
+static void
+android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B
+  (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jobject length_buf, jobject size_buf, jobject type_buf, jbyte name) {
+    jarray _lengthArray = (jarray) 0;
+    jint _lengthBufferOffset = (jint) 0;
+    jarray _sizeArray = (jarray) 0;
+    jint _sizeBufferOffset = (jint) 0;
+    jarray _typeArray = (jarray) 0;
+    jint _typeBufferOffset = (jint) 0;
+    jint _lengthRemaining;
+    GLsizei *length = (GLsizei *) 0;
+    jint _sizeRemaining;
+    GLint *size = (GLint *) 0;
+    jint _typeRemaining;
+    GLenum *type = (GLenum *) 0;
+
+    length = (GLsizei *)getPointer(_env, length_buf, &_lengthArray, &_lengthRemaining, &_lengthBufferOffset);
+    size = (GLint *)getPointer(_env, size_buf, &_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
+    type = (GLenum *)getPointer(_env, type_buf, &_typeArray, &_typeRemaining, &_typeBufferOffset);
+    if (length == NULL) {
+        char * _lengthBase = (char *)_env->GetPrimitiveArrayCritical(_lengthArray, (jboolean *) 0);
+        length = (GLsizei *) (_lengthBase + _lengthBufferOffset);
+    }
+    if (size == NULL) {
+        char * _sizeBase = (char *)_env->GetPrimitiveArrayCritical(_sizeArray, (jboolean *) 0);
+        size = (GLint *) (_sizeBase + _sizeBufferOffset);
+    }
+    if (type == NULL) {
+        char * _typeBase = (char *)_env->GetPrimitiveArrayCritical(_typeArray, (jboolean *) 0);
+        type = (GLenum *) (_typeBase + _typeBufferOffset);
+    }
+    glGetTransformFeedbackVarying(
+        (GLuint)program,
+        (GLuint)index,
+        (GLsizei)bufsize,
+        (GLsizei *)length,
+        (GLint *)size,
+        (GLenum *)type,
+        (char *)name
+    );
+    if (_typeArray) {
+        releasePointer(_env, _typeArray, type, JNI_TRUE);
+    }
+    if (_sizeArray) {
+        releasePointer(_env, _sizeArray, size, JNI_TRUE);
+    }
+    if (_lengthArray) {
+        releasePointer(_env, _lengthArray, length, JNI_TRUE);
+    }
+}
+
+/* void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name ) */
+static jstring
+android_glGetTransformFeedbackVarying1
+  (JNIEnv *_env, jobject _this, jint program, jint index, jintArray size_ref, jint sizeOffset, jintArray type_ref, jint typeOffset) {
+    jint _exception = 0;
+    const char * _exceptionType;
+    const char * _exceptionMessage;
+    GLint *size_base = (GLint *) 0;
+    jint _sizeRemaining;
+    GLint *size = (GLint *) 0;
+    GLenum *type_base = (GLenum *) 0;
+    jint _typeRemaining;
+    GLenum *type = (GLenum *) 0;
+
+    jstring result = 0;
+
+    GLint len = 0;
+    glGetProgramiv((GLuint)program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &len);
+    if (!len) {
+        return _env->NewStringUTF("");
+    }
+    char* buf = (char*) malloc(len);
+
+    if (buf == NULL) {
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory");
+        return NULL;
+    }
+    if (!size_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "size == null";
+        goto exit;
+    }
+    if (sizeOffset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "sizeOffset < 0";
+        goto exit;
+    }
+    _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset;
+    size_base = (GLint *)
+        _env->GetPrimitiveArrayCritical(size_ref, (jboolean *)0);
+    size = size_base + sizeOffset;
+
+    if (!type_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "type == null";
+        goto exit;
+    }
+    if (typeOffset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "typeOffset < 0";
+        goto exit;
+    }
+    _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset;
+    type_base = (GLenum *)
+        _env->GetPrimitiveArrayCritical(type_ref, (jboolean *)0);
+    type = type_base + typeOffset;
+
+    glGetTransformFeedbackVarying(
+        (GLuint)program,
+        (GLuint)index,
+        (GLsizei)len,
+        NULL,
+        (GLint *)size,
+        (GLenum *)type,
+        (char *)buf
+    );
+exit:
+    if (type_base) {
+        _env->ReleasePrimitiveArrayCritical(type_ref, type_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (size_base) {
+        _env->ReleasePrimitiveArrayCritical(size_ref, size_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception != 1) {
+        result = _env->NewStringUTF(buf);
+    }
+    if (buf) {
+        free(buf);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+    if (result == 0) {
+        result = _env->NewStringUTF("");
+    }
+
+    return result;
+}
+
+/* void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name ) */
+static jstring
+android_glGetTransformFeedbackVarying2
+  (JNIEnv *_env, jobject _this, jint program, jint index, jobject size_buf, jobject type_buf) {
+    jarray _sizeArray = (jarray) 0;
+    jint _sizeBufferOffset = (jint) 0;
+    jarray _typeArray = (jarray) 0;
+    jint _typeBufferOffset = (jint) 0;
+    jint _lengthRemaining;
+    GLsizei *length = (GLsizei *) 0;
+    jint _sizeRemaining;
+    GLint *size = (GLint *) 0;
+    jint _typeRemaining;
+    GLenum *type = (GLenum *) 0;
+
+    jstring result = 0;
+
+    GLint len = 0;
+    glGetProgramiv((GLuint)program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &len);
+    if (!len) {
+        return _env->NewStringUTF("");
+    }
+    char* buf = (char*) malloc(len);
+
+    if (buf == NULL) {
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory");
+        return NULL;
+    }
+
+    size = (GLint *)getPointer(_env, size_buf, &_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
+    type = (GLenum *)getPointer(_env, type_buf, &_typeArray, &_typeRemaining, &_typeBufferOffset);
+    if (size == NULL) {
+        char * _sizeBase = (char *)_env->GetPrimitiveArrayCritical(_sizeArray, (jboolean *) 0);
+        size = (GLint *) (_sizeBase + _sizeBufferOffset);
+    }
+    if (type == NULL) {
+        char * _typeBase = (char *)_env->GetPrimitiveArrayCritical(_typeArray, (jboolean *) 0);
+        type = (GLenum *) (_typeBase + _typeBufferOffset);
+    }
+    glGetTransformFeedbackVarying(
+        (GLuint)program,
+        (GLuint)index,
+        (GLsizei)len,
+        NULL,
+        (GLint *)size,
+        (GLenum *)type,
+        (char *)buf
+    );
+
+    if (_typeArray) {
+        releasePointer(_env, _typeArray, type, JNI_TRUE);
+    }
+    if (_sizeArray) {
+        releasePointer(_env, _sizeArray, size, JNI_TRUE);
+    }
+    result = _env->NewStringUTF(buf);
+    if (buf) {
+        free(buf);
+    }
+    return result;
+}
+/* void glVertexAttribIPointer ( GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) */
+static void
+android_glVertexAttribIPointerBounds__IIIILjava_nio_Buffer_2I
+  (JNIEnv *_env, jobject _this, jint index, jint size, jint type, jint stride, jobject pointer_buf, jint remaining) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLvoid *pointer = (GLvoid *) 0;
+
+    if (pointer_buf) {
+        pointer = (GLvoid *) getDirectBufferPointer(_env, pointer_buf);
+        if ( ! pointer ) {
+            return;
+        }
+    }
+    glVertexAttribIPointerBounds(
+        (GLuint)index,
+        (GLint)size,
+        (GLenum)type,
+        (GLsizei)stride,
+        (GLvoid *)pointer,
+        (GLsizei)remaining
+    );
+}
+
+/* void glVertexAttribIPointer ( GLuint index, GLint size, GLenum type, GLsizei stride, GLsizei offset ) */
+static void
+android_glVertexAttribIPointer__IIIII
+  (JNIEnv *_env, jobject _this, jint index, jint size, jint type, jint stride, jint offset) {
+    glVertexAttribIPointer(
+        (GLuint)index,
+        (GLint)size,
+        (GLenum)type,
+        (GLsizei)stride,
+        (GLvoid *)offset
+    );
+}
+
+/* void glGetVertexAttribIiv ( GLuint index, GLenum pname, GLint *params ) */
+static void
+android_glGetVertexAttribIiv__II_3II
+  (JNIEnv *_env, jobject _this, jint index, jint pname, jintArray params_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLint *params_base = (GLint *) 0;
+    jint _remaining;
+    GLint *params = (GLint *) 0;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(params_ref) - offset;
+    params_base = (GLint *)
+        _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+    params = params_base + offset;
+
+    glGetVertexAttribIiv(
+        (GLuint)index,
+        (GLenum)pname,
+        (GLint *)params
+    );
+
+exit:
+    if (params_base) {
+        _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetVertexAttribIiv ( GLuint index, GLenum pname, GLint *params ) */
+static void
+android_glGetVertexAttribIiv__IILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint index, jint pname, jobject params_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLint *params = (GLint *) 0;
+
+    params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining, &_bufferOffset);
+    if (params == NULL) {
+        char * _paramsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        params = (GLint *) (_paramsBase + _bufferOffset);
+    }
+    glGetVertexAttribIiv(
+        (GLuint)index,
+        (GLenum)pname,
+        (GLint *)params
+    );
+    if (_array) {
+        releasePointer(_env, _array, params, JNI_TRUE);
+    }
+}
+
+/* void glGetVertexAttribIuiv ( GLuint index, GLenum pname, GLuint *params ) */
+static void
+android_glGetVertexAttribIuiv__II_3II
+  (JNIEnv *_env, jobject _this, jint index, jint pname, jintArray params_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *params_base = (GLuint *) 0;
+    jint _remaining;
+    GLuint *params = (GLuint *) 0;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(params_ref) - offset;
+    params_base = (GLuint *)
+        _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+    params = params_base + offset;
+
+    glGetVertexAttribIuiv(
+        (GLuint)index,
+        (GLenum)pname,
+        (GLuint *)params
+    );
+
+exit:
+    if (params_base) {
+        _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetVertexAttribIuiv ( GLuint index, GLenum pname, GLuint *params ) */
+static void
+android_glGetVertexAttribIuiv__IILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint index, jint pname, jobject params_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLuint *params = (GLuint *) 0;
+
+    params = (GLuint *)getPointer(_env, params_buf, &_array, &_remaining, &_bufferOffset);
+    if (params == NULL) {
+        char * _paramsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        params = (GLuint *) (_paramsBase + _bufferOffset);
+    }
+    glGetVertexAttribIuiv(
+        (GLuint)index,
+        (GLenum)pname,
+        (GLuint *)params
+    );
+    if (_array) {
+        releasePointer(_env, _array, params, JNI_TRUE);
+    }
+}
+
+/* void glVertexAttribI4i ( GLuint index, GLint x, GLint y, GLint z, GLint w ) */
+static void
+android_glVertexAttribI4i__IIIII
+  (JNIEnv *_env, jobject _this, jint index, jint x, jint y, jint z, jint w) {
+    glVertexAttribI4i(
+        (GLuint)index,
+        (GLint)x,
+        (GLint)y,
+        (GLint)z,
+        (GLint)w
+    );
+}
+
+/* void glVertexAttribI4ui ( GLuint index, GLuint x, GLuint y, GLuint z, GLuint w ) */
+static void
+android_glVertexAttribI4ui__IIIII
+  (JNIEnv *_env, jobject _this, jint index, jint x, jint y, jint z, jint w) {
+    glVertexAttribI4ui(
+        (GLuint)index,
+        (GLuint)x,
+        (GLuint)y,
+        (GLuint)z,
+        (GLuint)w
+    );
+}
+
+/* void glVertexAttribI4iv ( GLuint index, const GLint *v ) */
+static void
+android_glVertexAttribI4iv__I_3II
+  (JNIEnv *_env, jobject _this, jint index, jintArray v_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLint *v_base = (GLint *) 0;
+    jint _remaining;
+    GLint *v = (GLint *) 0;
+
+    if (!v_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "v == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(v_ref) - offset;
+    v_base = (GLint *)
+        _env->GetPrimitiveArrayCritical(v_ref, (jboolean *)0);
+    v = v_base + offset;
+
+    glVertexAttribI4iv(
+        (GLuint)index,
+        (GLint *)v
+    );
+
+exit:
+    if (v_base) {
+        _env->ReleasePrimitiveArrayCritical(v_ref, v_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glVertexAttribI4iv ( GLuint index, const GLint *v ) */
+static void
+android_glVertexAttribI4iv__ILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint index, jobject v_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLint *v = (GLint *) 0;
+
+    v = (GLint *)getPointer(_env, v_buf, &_array, &_remaining, &_bufferOffset);
+    if (v == NULL) {
+        char * _vBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        v = (GLint *) (_vBase + _bufferOffset);
+    }
+    glVertexAttribI4iv(
+        (GLuint)index,
+        (GLint *)v
+    );
+    if (_array) {
+        releasePointer(_env, _array, v, JNI_FALSE);
+    }
+}
+
+/* void glVertexAttribI4uiv ( GLuint index, const GLuint *v ) */
+static void
+android_glVertexAttribI4uiv__I_3II
+  (JNIEnv *_env, jobject _this, jint index, jintArray v_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *v_base = (GLuint *) 0;
+    jint _remaining;
+    GLuint *v = (GLuint *) 0;
+
+    if (!v_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "v == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(v_ref) - offset;
+    v_base = (GLuint *)
+        _env->GetPrimitiveArrayCritical(v_ref, (jboolean *)0);
+    v = v_base + offset;
+
+    glVertexAttribI4uiv(
+        (GLuint)index,
+        (GLuint *)v
+    );
+
+exit:
+    if (v_base) {
+        _env->ReleasePrimitiveArrayCritical(v_ref, v_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glVertexAttribI4uiv ( GLuint index, const GLuint *v ) */
+static void
+android_glVertexAttribI4uiv__ILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint index, jobject v_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLuint *v = (GLuint *) 0;
+
+    v = (GLuint *)getPointer(_env, v_buf, &_array, &_remaining, &_bufferOffset);
+    if (v == NULL) {
+        char * _vBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        v = (GLuint *) (_vBase + _bufferOffset);
+    }
+    glVertexAttribI4uiv(
+        (GLuint)index,
+        (GLuint *)v
+    );
+    if (_array) {
+        releasePointer(_env, _array, v, JNI_FALSE);
+    }
+}
+
+/* void glGetUniformuiv ( GLuint program, GLint location, GLuint *params ) */
+static void
+android_glGetUniformuiv__II_3II
+  (JNIEnv *_env, jobject _this, jint program, jint location, jintArray params_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *params_base = (GLuint *) 0;
+    jint _remaining;
+    GLuint *params = (GLuint *) 0;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(params_ref) - offset;
+    params_base = (GLuint *)
+        _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+    params = params_base + offset;
+
+    glGetUniformuiv(
+        (GLuint)program,
+        (GLint)location,
+        (GLuint *)params
+    );
+
+exit:
+    if (params_base) {
+        _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetUniformuiv ( GLuint program, GLint location, GLuint *params ) */
+static void
+android_glGetUniformuiv__IILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint program, jint location, jobject params_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLuint *params = (GLuint *) 0;
+
+    params = (GLuint *)getPointer(_env, params_buf, &_array, &_remaining, &_bufferOffset);
+    if (params == NULL) {
+        char * _paramsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        params = (GLuint *) (_paramsBase + _bufferOffset);
+    }
+    glGetUniformuiv(
+        (GLuint)program,
+        (GLint)location,
+        (GLuint *)params
+    );
+    if (_array) {
+        releasePointer(_env, _array, params, JNI_TRUE);
+    }
+}
+
+/* GLint glGetFragDataLocation ( GLuint program, const GLchar *name ) */
+static jint
+android_glGetFragDataLocation__ILjava_lang_String_2
+  (JNIEnv *_env, jobject _this, jint program, jstring name) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLint _returnValue = 0;
+    const char* _nativename = 0;
+
+    if (!name) {
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "name == null";
+        goto exit;
+    }
+    _nativename = _env->GetStringUTFChars(name, 0);
+
+    _returnValue = glGetFragDataLocation(
+        (GLuint)program,
+        (GLchar *)_nativename
+    );
+
+exit:
+    if (_nativename) {
+        _env->ReleaseStringUTFChars(name, _nativename);
+    }
+
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+    return (jint)_returnValue;
+}
+
+/* void glUniform1ui ( GLint location, GLuint v0 ) */
+static void
+android_glUniform1ui__II
+  (JNIEnv *_env, jobject _this, jint location, jint v0) {
+    glUniform1ui(
+        (GLint)location,
+        (GLuint)v0
+    );
+}
+
+/* void glUniform2ui ( GLint location, GLuint v0, GLuint v1 ) */
+static void
+android_glUniform2ui__III
+  (JNIEnv *_env, jobject _this, jint location, jint v0, jint v1) {
+    glUniform2ui(
+        (GLint)location,
+        (GLuint)v0,
+        (GLuint)v1
+    );
+}
+
+/* void glUniform3ui ( GLint location, GLuint v0, GLuint v1, GLuint v2 ) */
+static void
+android_glUniform3ui__IIII
+  (JNIEnv *_env, jobject _this, jint location, jint v0, jint v1, jint v2) {
+    glUniform3ui(
+        (GLint)location,
+        (GLuint)v0,
+        (GLuint)v1,
+        (GLuint)v2
+    );
+}
+
+/* void glUniform4ui ( GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3 ) */
+static void
+android_glUniform4ui__IIIII
+  (JNIEnv *_env, jobject _this, jint location, jint v0, jint v1, jint v2, jint v3) {
+    glUniform4ui(
+        (GLint)location,
+        (GLuint)v0,
+        (GLuint)v1,
+        (GLuint)v2,
+        (GLuint)v3
+    );
+}
+
+/* void glUniform1uiv ( GLint location, GLsizei count, const GLuint *value ) */
+static void
+android_glUniform1uiv__II_3II
+  (JNIEnv *_env, jobject _this, jint location, jint count, jintArray value_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *value_base = (GLuint *) 0;
+    jint _remaining;
+    GLuint *value = (GLuint *) 0;
+
+    if (!value_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(value_ref) - offset;
+    value_base = (GLuint *)
+        _env->GetPrimitiveArrayCritical(value_ref, (jboolean *)0);
+    value = value_base + offset;
+
+    glUniform1uiv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLuint *)value
+    );
+
+exit:
+    if (value_base) {
+        _env->ReleasePrimitiveArrayCritical(value_ref, value_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glUniform1uiv ( GLint location, GLsizei count, const GLuint *value ) */
+static void
+android_glUniform1uiv__IILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint location, jint count, jobject value_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLuint *value = (GLuint *) 0;
+
+    value = (GLuint *)getPointer(_env, value_buf, &_array, &_remaining, &_bufferOffset);
+    if (value == NULL) {
+        char * _valueBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        value = (GLuint *) (_valueBase + _bufferOffset);
+    }
+    glUniform1uiv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLuint *)value
+    );
+    if (_array) {
+        releasePointer(_env, _array, value, JNI_FALSE);
+    }
+}
+
+/* void glUniform2uiv ( GLint location, GLsizei count, const GLuint *value ) */
+static void
+android_glUniform2uiv__II_3II
+  (JNIEnv *_env, jobject _this, jint location, jint count, jintArray value_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *value_base = (GLuint *) 0;
+    jint _remaining;
+    GLuint *value = (GLuint *) 0;
+
+    if (!value_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(value_ref) - offset;
+    value_base = (GLuint *)
+        _env->GetPrimitiveArrayCritical(value_ref, (jboolean *)0);
+    value = value_base + offset;
+
+    glUniform2uiv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLuint *)value
+    );
+
+exit:
+    if (value_base) {
+        _env->ReleasePrimitiveArrayCritical(value_ref, value_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glUniform2uiv ( GLint location, GLsizei count, const GLuint *value ) */
+static void
+android_glUniform2uiv__IILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint location, jint count, jobject value_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLuint *value = (GLuint *) 0;
+
+    value = (GLuint *)getPointer(_env, value_buf, &_array, &_remaining, &_bufferOffset);
+    if (value == NULL) {
+        char * _valueBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        value = (GLuint *) (_valueBase + _bufferOffset);
+    }
+    glUniform2uiv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLuint *)value
+    );
+    if (_array) {
+        releasePointer(_env, _array, value, JNI_FALSE);
+    }
+}
+
+/* void glUniform3uiv ( GLint location, GLsizei count, const GLuint *value ) */
+static void
+android_glUniform3uiv__II_3II
+  (JNIEnv *_env, jobject _this, jint location, jint count, jintArray value_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *value_base = (GLuint *) 0;
+    jint _remaining;
+    GLuint *value = (GLuint *) 0;
+
+    if (!value_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(value_ref) - offset;
+    value_base = (GLuint *)
+        _env->GetPrimitiveArrayCritical(value_ref, (jboolean *)0);
+    value = value_base + offset;
+
+    glUniform3uiv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLuint *)value
+    );
+
+exit:
+    if (value_base) {
+        _env->ReleasePrimitiveArrayCritical(value_ref, value_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glUniform3uiv ( GLint location, GLsizei count, const GLuint *value ) */
+static void
+android_glUniform3uiv__IILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint location, jint count, jobject value_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLuint *value = (GLuint *) 0;
+
+    value = (GLuint *)getPointer(_env, value_buf, &_array, &_remaining, &_bufferOffset);
+    if (value == NULL) {
+        char * _valueBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        value = (GLuint *) (_valueBase + _bufferOffset);
+    }
+    glUniform3uiv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLuint *)value
+    );
+    if (_array) {
+        releasePointer(_env, _array, value, JNI_FALSE);
+    }
+}
+
+/* void glUniform4uiv ( GLint location, GLsizei count, const GLuint *value ) */
+static void
+android_glUniform4uiv__II_3II
+  (JNIEnv *_env, jobject _this, jint location, jint count, jintArray value_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *value_base = (GLuint *) 0;
+    jint _remaining;
+    GLuint *value = (GLuint *) 0;
+
+    if (!value_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(value_ref) - offset;
+    value_base = (GLuint *)
+        _env->GetPrimitiveArrayCritical(value_ref, (jboolean *)0);
+    value = value_base + offset;
+
+    glUniform4uiv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLuint *)value
+    );
+
+exit:
+    if (value_base) {
+        _env->ReleasePrimitiveArrayCritical(value_ref, value_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glUniform4uiv ( GLint location, GLsizei count, const GLuint *value ) */
+static void
+android_glUniform4uiv__IILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint location, jint count, jobject value_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLuint *value = (GLuint *) 0;
+
+    value = (GLuint *)getPointer(_env, value_buf, &_array, &_remaining, &_bufferOffset);
+    if (value == NULL) {
+        char * _valueBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        value = (GLuint *) (_valueBase + _bufferOffset);
+    }
+    glUniform4uiv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLuint *)value
+    );
+    if (_array) {
+        releasePointer(_env, _array, value, JNI_FALSE);
+    }
+}
+
+/* void glClearBufferiv ( GLenum buffer, GLint drawbuffer, const GLint *value ) */
+static void
+android_glClearBufferiv__II_3II
+  (JNIEnv *_env, jobject _this, jint buffer, jint drawbuffer, jintArray value_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLint *value_base = (GLint *) 0;
+    jint _remaining;
+    GLint *value = (GLint *) 0;
+
+    if (!value_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(value_ref) - offset;
+    value_base = (GLint *)
+        _env->GetPrimitiveArrayCritical(value_ref, (jboolean *)0);
+    value = value_base + offset;
+
+    glClearBufferiv(
+        (GLenum)buffer,
+        (GLint)drawbuffer,
+        (GLint *)value
+    );
+
+exit:
+    if (value_base) {
+        _env->ReleasePrimitiveArrayCritical(value_ref, value_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glClearBufferiv ( GLenum buffer, GLint drawbuffer, const GLint *value ) */
+static void
+android_glClearBufferiv__IILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint buffer, jint drawbuffer, jobject value_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLint *value = (GLint *) 0;
+
+    value = (GLint *)getPointer(_env, value_buf, &_array, &_remaining, &_bufferOffset);
+    if (value == NULL) {
+        char * _valueBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        value = (GLint *) (_valueBase + _bufferOffset);
+    }
+    glClearBufferiv(
+        (GLenum)buffer,
+        (GLint)drawbuffer,
+        (GLint *)value
+    );
+    if (_array) {
+        releasePointer(_env, _array, value, JNI_FALSE);
+    }
+}
+
+/* void glClearBufferuiv ( GLenum buffer, GLint drawbuffer, const GLuint *value ) */
+static void
+android_glClearBufferuiv__II_3II
+  (JNIEnv *_env, jobject _this, jint buffer, jint drawbuffer, jintArray value_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *value_base = (GLuint *) 0;
+    jint _remaining;
+    GLuint *value = (GLuint *) 0;
+
+    if (!value_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(value_ref) - offset;
+    value_base = (GLuint *)
+        _env->GetPrimitiveArrayCritical(value_ref, (jboolean *)0);
+    value = value_base + offset;
+
+    glClearBufferuiv(
+        (GLenum)buffer,
+        (GLint)drawbuffer,
+        (GLuint *)value
+    );
+
+exit:
+    if (value_base) {
+        _env->ReleasePrimitiveArrayCritical(value_ref, value_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glClearBufferuiv ( GLenum buffer, GLint drawbuffer, const GLuint *value ) */
+static void
+android_glClearBufferuiv__IILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint buffer, jint drawbuffer, jobject value_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLuint *value = (GLuint *) 0;
+
+    value = (GLuint *)getPointer(_env, value_buf, &_array, &_remaining, &_bufferOffset);
+    if (value == NULL) {
+        char * _valueBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        value = (GLuint *) (_valueBase + _bufferOffset);
+    }
+    glClearBufferuiv(
+        (GLenum)buffer,
+        (GLint)drawbuffer,
+        (GLuint *)value
+    );
+    if (_array) {
+        releasePointer(_env, _array, value, JNI_FALSE);
+    }
+}
+
+/* void glClearBufferfv ( GLenum buffer, GLint drawbuffer, const GLfloat *value ) */
+static void
+android_glClearBufferfv__II_3FI
+  (JNIEnv *_env, jobject _this, jint buffer, jint drawbuffer, jfloatArray value_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLfloat *value_base = (GLfloat *) 0;
+    jint _remaining;
+    GLfloat *value = (GLfloat *) 0;
+
+    if (!value_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(value_ref) - offset;
+    value_base = (GLfloat *)
+        _env->GetPrimitiveArrayCritical(value_ref, (jboolean *)0);
+    value = value_base + offset;
+
+    glClearBufferfv(
+        (GLenum)buffer,
+        (GLint)drawbuffer,
+        (GLfloat *)value
+    );
+
+exit:
+    if (value_base) {
+        _env->ReleasePrimitiveArrayCritical(value_ref, value_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glClearBufferfv ( GLenum buffer, GLint drawbuffer, const GLfloat *value ) */
+static void
+android_glClearBufferfv__IILjava_nio_FloatBuffer_2
+  (JNIEnv *_env, jobject _this, jint buffer, jint drawbuffer, jobject value_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLfloat *value = (GLfloat *) 0;
+
+    value = (GLfloat *)getPointer(_env, value_buf, &_array, &_remaining, &_bufferOffset);
+    if (value == NULL) {
+        char * _valueBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        value = (GLfloat *) (_valueBase + _bufferOffset);
+    }
+    glClearBufferfv(
+        (GLenum)buffer,
+        (GLint)drawbuffer,
+        (GLfloat *)value
+    );
+    if (_array) {
+        releasePointer(_env, _array, value, JNI_FALSE);
+    }
+}
+
+/* void glClearBufferfi ( GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil ) */
+static void
+android_glClearBufferfi__IIFI
+  (JNIEnv *_env, jobject _this, jint buffer, jint drawbuffer, jfloat depth, jint stencil) {
+    glClearBufferfi(
+        (GLenum)buffer,
+        (GLint)drawbuffer,
+        (GLfloat)depth,
+        (GLint)stencil
+    );
+}
+
+/* const GLubyte * glGetStringi ( GLenum name, GLuint index ) */
+static jstring
+android_glGetStringi__II
+  (JNIEnv *_env, jobject _this, jint name, jint index) {
+    const GLubyte* _chars = glGetStringi((GLenum)name, (GLuint)index);
+    return _env->NewStringUTF((const char*)_chars);
+}
+
+/* void glCopyBufferSubData ( GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size ) */
+static void
+android_glCopyBufferSubData__IIIII
+  (JNIEnv *_env, jobject _this, jint readTarget, jint writeTarget, jint readOffset, jint writeOffset, jint size) {
+    glCopyBufferSubData(
+        (GLenum)readTarget,
+        (GLenum)writeTarget,
+        (GLintptr)readOffset,
+        (GLintptr)writeOffset,
+        (GLsizeiptr)size
+    );
+}
+
+/* void glGetUniformIndices ( GLuint program, GLsizei uniformCount, const GLchar *const *uniformNames, GLuint *uniformIndices ) */
+static
+void
+android_glGetUniformIndices_array
+    (JNIEnv *_env, jobject _this, jint program, jobjectArray uniformNames_ref, jintArray uniformIndices_ref, jint uniformIndicesOffset) {
+    jint _exception = 0;
+    const char* _exceptionType = NULL;
+    const char* _exceptionMessage = NULL;
+    jint _count = 0;
+    jint _i;
+    const char** _names = NULL;
+    GLuint* _indices_base = NULL;
+    GLuint* _indices = NULL;
+
+    if (!uniformNames_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "uniformNames == null";
+        goto exit;
+    }
+    _count = _env->GetArrayLength(uniformNames_ref);
+    _names = (const char**)calloc(_count, sizeof(const char*));
+    for (_i = 0; _i < _count; _i++) {
+        jstring _name = (jstring)_env->GetObjectArrayElement(uniformNames_ref, _i);
+        if (!_name) {
+            _exception = 1;
+            _exceptionType = "java/lang/IllegalArgumentException";
+            _exceptionMessage = "null uniformNames element";
+            goto exit;
+        }
+        _names[_i] = _env->GetStringUTFChars(_name, 0);
+    }
+
+    if (!uniformIndices_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "uniformIndices == null";
+        goto exit;
+    }
+    if (uniformIndicesOffset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "uniformIndicesOffset < 0";
+        goto exit;
+    }
+    if (_env->GetArrayLength(uniformIndices_ref) - uniformIndicesOffset < _count) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "not enough space in uniformIndices";
+        goto exit;
+    }
+    _indices_base = (GLuint*)_env->GetPrimitiveArrayCritical(
+            uniformIndices_ref, 0);
+    _indices = _indices_base + uniformIndicesOffset;
+
+    glGetUniformIndices(program, _count, _names, _indices);
+
+exit:
+    if (_indices_base) {
+        _env->ReleasePrimitiveArrayCritical(uniformIndices_ref, _indices_base,
+                _exception ? JNI_ABORT : 0);
+    }
+    for (_i = _count - 1; _i >= 0; _i--) {
+        if (_names[_i]) {
+            jstring _name = (jstring)_env->GetObjectArrayElement(uniformNames_ref, _i);
+            if (_name) {
+                _env->ReleaseStringUTFChars(_name, _names[_i]);
+            }
+        }
+    }
+    free(_names);
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetUniformIndices ( GLuint program, GLsizei uniformCount, const GLchar *const *uniformNames, GLuint *uniformIndices ) */
+static
+void
+android_glGetUniformIndices_buffer
+    (JNIEnv *_env, jobject _this, jint program, jobjectArray uniformNames_ref, jobject uniformIndices_buf) {
+    jint _exception = 0;
+    const char* _exceptionType = NULL;
+    const char* _exceptionMessage = NULL;
+    jint _count = 0;
+    jint _i;
+    const char** _names = NULL;
+    jarray _uniformIndicesArray = (jarray)0;
+    jint _uniformIndicesRemaining;
+    jint _uniformIndicesOffset = 0;
+    GLuint* _indices = NULL;
+    char* _indicesBase = NULL;
+
+    if (!uniformNames_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "uniformNames == null";
+        goto exit;
+    }
+    if (!uniformIndices_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "uniformIndices == null";
+        goto exit;
+    }
+
+    _count = _env->GetArrayLength(uniformNames_ref);
+    _names = (const char**)calloc(_count, sizeof(const char*));
+    for (_i = 0; _i < _count; _i++) {
+        jstring _name = (jstring)_env->GetObjectArrayElement(uniformNames_ref, _i);
+        if (!_name) {
+            _exception = 1;
+            _exceptionType = "java/lang/IllegalArgumentException";
+            _exceptionMessage = "null uniformNames element";
+            goto exit;
+        }
+        _names[_i] = _env->GetStringUTFChars(_name, 0);
+    }
+
+    _indices = (GLuint*)getPointer(_env, uniformIndices_buf,
+            &_uniformIndicesArray, &_uniformIndicesRemaining,
+            &_uniformIndicesOffset);
+    if (!_indices) {
+        _indicesBase = (char*)_env->GetPrimitiveArrayCritical(
+                _uniformIndicesArray, 0);
+        _indices = (GLuint*)(_indicesBase + _uniformIndicesOffset);
+    }
+    if (_uniformIndicesRemaining < _count) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "not enough space in uniformIndices";
+        goto exit;
+    }
+
+    glGetUniformIndices(program, _count, _names, _indices);
+
+exit:
+    if (_uniformIndicesArray) {
+        releasePointer(_env, _uniformIndicesArray, _indicesBase, JNI_TRUE);
+    }
+    for (_i = _count - 1; _i >= 0; _i--) {
+        if (_names[_i]) {
+            jstring _name = (jstring)_env->GetObjectArrayElement(uniformNames_ref, _i);
+            if (_name) {
+                _env->ReleaseStringUTFChars(_name, _names[_i]);
+            }
+        }
+    }
+    free(_names);
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetActiveUniformsiv ( GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params ) */
+static void
+android_glGetActiveUniformsiv__II_3III_3II
+  (JNIEnv *_env, jobject _this, jint program, jint uniformCount, jintArray uniformIndices_ref, jint uniformIndicesOffset, jint pname, jintArray params_ref, jint paramsOffset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *uniformIndices_base = (GLuint *) 0;
+    jint _uniformIndicesRemaining;
+    GLuint *uniformIndices = (GLuint *) 0;
+    GLint *params_base = (GLint *) 0;
+    jint _paramsRemaining;
+    GLint *params = (GLint *) 0;
+
+    if (!uniformIndices_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "uniformIndices == null";
+        goto exit;
+    }
+    if (uniformIndicesOffset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "uniformIndicesOffset < 0";
+        goto exit;
+    }
+    _uniformIndicesRemaining = _env->GetArrayLength(uniformIndices_ref) - uniformIndicesOffset;
+    uniformIndices_base = (GLuint *)
+        _env->GetPrimitiveArrayCritical(uniformIndices_ref, (jboolean *)0);
+    uniformIndices = uniformIndices_base + uniformIndicesOffset;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+    if (paramsOffset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "paramsOffset < 0";
+        goto exit;
+    }
+    _paramsRemaining = _env->GetArrayLength(params_ref) - paramsOffset;
+    params_base = (GLint *)
+        _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+    params = params_base + paramsOffset;
+
+    glGetActiveUniformsiv(
+        (GLuint)program,
+        (GLsizei)uniformCount,
+        (GLuint *)uniformIndices,
+        (GLenum)pname,
+        (GLint *)params
+    );
+
+exit:
+    if (params_base) {
+        _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (uniformIndices_base) {
+        _env->ReleasePrimitiveArrayCritical(uniformIndices_ref, uniformIndices_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetActiveUniformsiv ( GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params ) */
+static void
+android_glGetActiveUniformsiv__IILjava_nio_IntBuffer_2ILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint program, jint uniformCount, jobject uniformIndices_buf, jint pname, jobject params_buf) {
+    jarray _uniformIndicesArray = (jarray) 0;
+    jint _uniformIndicesBufferOffset = (jint) 0;
+    jarray _paramsArray = (jarray) 0;
+    jint _paramsBufferOffset = (jint) 0;
+    jint _uniformIndicesRemaining;
+    GLuint *uniformIndices = (GLuint *) 0;
+    jint _paramsRemaining;
+    GLint *params = (GLint *) 0;
+
+    uniformIndices = (GLuint *)getPointer(_env, uniformIndices_buf, &_uniformIndicesArray, &_uniformIndicesRemaining, &_uniformIndicesBufferOffset);
+    params = (GLint *)getPointer(_env, params_buf, &_paramsArray, &_paramsRemaining, &_paramsBufferOffset);
+    if (uniformIndices == NULL) {
+        char * _uniformIndicesBase = (char *)_env->GetPrimitiveArrayCritical(_uniformIndicesArray, (jboolean *) 0);
+        uniformIndices = (GLuint *) (_uniformIndicesBase + _uniformIndicesBufferOffset);
+    }
+    if (params == NULL) {
+        char * _paramsBase = (char *)_env->GetPrimitiveArrayCritical(_paramsArray, (jboolean *) 0);
+        params = (GLint *) (_paramsBase + _paramsBufferOffset);
+    }
+    glGetActiveUniformsiv(
+        (GLuint)program,
+        (GLsizei)uniformCount,
+        (GLuint *)uniformIndices,
+        (GLenum)pname,
+        (GLint *)params
+    );
+    if (_paramsArray) {
+        releasePointer(_env, _paramsArray, params, JNI_TRUE);
+    }
+    if (_uniformIndicesArray) {
+        releasePointer(_env, _uniformIndicesArray, uniformIndices, JNI_FALSE);
+    }
+}
+
+/* GLuint glGetUniformBlockIndex ( GLuint program, const GLchar *uniformBlockName ) */
+static jint
+android_glGetUniformBlockIndex__ILjava_lang_String_2
+  (JNIEnv *_env, jobject _this, jint program, jstring uniformBlockName) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint _returnValue = 0;
+    const char* _nativeuniformBlockName = 0;
+
+    if (!uniformBlockName) {
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "uniformBlockName == null";
+        goto exit;
+    }
+    _nativeuniformBlockName = _env->GetStringUTFChars(uniformBlockName, 0);
+
+    _returnValue = glGetUniformBlockIndex(
+        (GLuint)program,
+        (GLchar *)_nativeuniformBlockName
+    );
+
+exit:
+    if (_nativeuniformBlockName) {
+        _env->ReleaseStringUTFChars(uniformBlockName, _nativeuniformBlockName);
+    }
+
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+    return (jint)_returnValue;
+}
+
+/* void glGetActiveUniformBlockiv ( GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params ) */
+static void
+android_glGetActiveUniformBlockiv__III_3II
+  (JNIEnv *_env, jobject _this, jint program, jint uniformBlockIndex, jint pname, jintArray params_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLint *params_base = (GLint *) 0;
+    jint _remaining;
+    GLint *params = (GLint *) 0;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(params_ref) - offset;
+    params_base = (GLint *)
+        _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+    params = params_base + offset;
+
+    glGetActiveUniformBlockiv(
+        (GLuint)program,
+        (GLuint)uniformBlockIndex,
+        (GLenum)pname,
+        (GLint *)params
+    );
+
+exit:
+    if (params_base) {
+        _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetActiveUniformBlockiv ( GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params ) */
+static void
+android_glGetActiveUniformBlockiv__IIILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint program, jint uniformBlockIndex, jint pname, jobject params_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLint *params = (GLint *) 0;
+
+    params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining, &_bufferOffset);
+    if (params == NULL) {
+        char * _paramsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        params = (GLint *) (_paramsBase + _bufferOffset);
+    }
+    glGetActiveUniformBlockiv(
+        (GLuint)program,
+        (GLuint)uniformBlockIndex,
+        (GLenum)pname,
+        (GLint *)params
+    );
+    if (_array) {
+        releasePointer(_env, _array, params, JNI_TRUE);
+    }
+}
+
+/* void glGetActiveUniformBlockName ( GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName ) */
+static void
+android_glGetActiveUniformBlockName_III_3II_3BI
+    (JNIEnv* _env, jobject _this, jint program, jint uniformBlockIndex, int bufSize, jintArray length_ref, jint lengthOffset, jbyteArray name_ref, jint nameOffset) {
+    jint _exception = 0;
+    const char* _exceptionType;
+    const char* _exceptionMessage;
+    GLsizei* _length_base = (GLsizei*)0;
+    jint _lengthRemaining;
+    GLsizei* _length = (GLsizei*)0;
+    GLchar* _name_base = (GLchar*)0;
+    jint _nameRemaining;
+    GLchar* _name = (GLchar*)0;
+
+    if (!length_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "length == null";
+        goto exit;
+    }
+    if (lengthOffset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "lengthOffset < 0";
+        goto exit;
+    }
+    _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset;
+    _length_base = (GLsizei*)_env->GetPrimitiveArrayCritical(
+            length_ref, (jboolean*)0);
+    _length = _length_base + lengthOffset;
+
+    if (!name_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "uniformBlockName == null";
+        goto exit;
+    }
+    if (nameOffset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "uniformBlockNameOffset < 0";
+        goto exit;
+    }
+    _nameRemaining = _env->GetArrayLength(name_ref) - nameOffset;
+    _name_base = (GLchar*)_env->GetPrimitiveArrayCritical(
+            name_ref, (jboolean*)0);
+    _name = _name_base + nameOffset;
+
+    glGetActiveUniformBlockName(
+        (GLuint)program,
+        (GLuint)uniformBlockIndex,
+        (GLsizei)bufSize,
+        (GLsizei*)_length,
+        (GLchar*)_name
+    );
+
+exit:
+    if (_name_base) {
+        _env->ReleasePrimitiveArrayCritical(name_ref, _name_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_length_base) {
+        _env->ReleasePrimitiveArrayCritical(length_ref, _length_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetActiveUniformBlockName ( GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName ) */
+static void
+android_glGetActiveUniformBlockName_IILjava_nio_Buffer_2Ljava_nio_Buffer_2
+    (JNIEnv* _env, jobject _this, jint program, jint uniformBlockIndex, jobject length_buf, jobject uniformBlockName_buf) {
+    jint _exception = 0;
+    const char* _exceptionType;
+    const char* _exceptionMessage;
+    jarray _lengthArray = (jarray)0;
+    jint _lengthBufferOffset = (jint)0;
+    GLsizei* _length = (GLsizei*)0;
+    jint _lengthRemaining;
+    jarray _nameArray = (jarray)0;
+    jint _nameBufferOffset = (jint)0;
+    GLchar* _name = (GLchar*)0;
+    jint _nameRemaining;
+
+    _length = (GLsizei*)getPointer(_env, length_buf, &_lengthArray, &_lengthRemaining, &_lengthBufferOffset);
+    if (_length == NULL) {
+        GLsizei* _lengthBase = (GLsizei*)_env->GetPrimitiveArrayCritical(_lengthArray, (jboolean*)0);
+        _length = (GLsizei*)(_lengthBase + _lengthBufferOffset);
+    }
+
+    _name = (GLchar*)getPointer(_env, uniformBlockName_buf, &_nameArray, &_nameRemaining, &_nameBufferOffset);
+    if (_name == NULL) {
+        GLchar* _nameBase = (GLchar*)_env->GetPrimitiveArrayCritical(_nameArray, (jboolean*)0);
+        _name = (GLchar*)(_nameBase + _nameBufferOffset);
+    }
+
+    glGetActiveUniformBlockName(
+        (GLuint)program,
+        (GLuint)uniformBlockIndex,
+        (GLsizei)_nameRemaining,
+        _length, _name
+    );
+    if (_nameArray) {
+        releasePointer(_env, _nameArray, _name, JNI_TRUE);
+    }
+    if (_lengthArray) {
+        releasePointer(_env, _lengthArray, _length, JNI_TRUE);
+    }
+}
+
+/* void glGetActiveUniformBlockName ( GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName ) */
+static jstring
+android_glGetActiveUniformBlockName_II
+    (JNIEnv *_env, jobject _this, jint program, jint uniformBlockIndex) {
+    GLint len = 0;
+    glGetActiveUniformBlockiv((GLuint)program, (GLuint)uniformBlockIndex,
+            GL_UNIFORM_BLOCK_NAME_LENGTH, &len);
+    GLchar* name = (GLchar*)malloc(len);
+    glGetActiveUniformBlockName((GLuint)program, (GLuint)uniformBlockIndex,
+        len, NULL, name);
+    jstring result = _env->NewStringUTF(name);
+    free(name);
+    return result;
+}
+
+/* void glUniformBlockBinding ( GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding ) */
+static void
+android_glUniformBlockBinding__III
+  (JNIEnv *_env, jobject _this, jint program, jint uniformBlockIndex, jint uniformBlockBinding) {
+    glUniformBlockBinding(
+        (GLuint)program,
+        (GLuint)uniformBlockIndex,
+        (GLuint)uniformBlockBinding
+    );
+}
+
+/* void glDrawArraysInstanced ( GLenum mode, GLint first, GLsizei count, GLsizei instanceCount ) */
+static void
+android_glDrawArraysInstanced__IIII
+  (JNIEnv *_env, jobject _this, jint mode, jint first, jint count, jint instanceCount) {
+    glDrawArraysInstanced(
+        (GLenum)mode,
+        (GLint)first,
+        (GLsizei)count,
+        (GLsizei)instanceCount
+    );
+}
+
+/* void glDrawElementsInstanced ( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instanceCount ) */
+static void
+android_glDrawElementsInstanced__IIILjava_nio_Buffer_2I
+  (JNIEnv *_env, jobject _this, jint mode, jint count, jint type, jobject indices_buf, jint instanceCount) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLvoid *indices = (GLvoid *) 0;
+
+    indices = (GLvoid *)getPointer(_env, indices_buf, &_array, &_remaining, &_bufferOffset);
+    if (indices == NULL) {
+        char * _indicesBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        indices = (GLvoid *) (_indicesBase + _bufferOffset);
+    }
+    glDrawElementsInstanced(
+        (GLenum)mode,
+        (GLsizei)count,
+        (GLenum)type,
+        (GLvoid *)indices,
+        (GLsizei)instanceCount
+    );
+    if (_array) {
+        releasePointer(_env, _array, indices, JNI_FALSE);
+    }
+}
+
+/* void glDrawElementsInstanced ( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instanceCount ) */
+static void
+android_glDrawElementsInstanced__IIIII
+  (JNIEnv *_env, jobject _this, jint mode, jint count, jint type, jint indicesOffset, jint instanceCount) {
+    glDrawElementsInstanced(
+        (GLenum)mode,
+        (GLsizei)count,
+        (GLenum)type,
+        (GLvoid *)indicesOffset,
+        (GLsizei)instanceCount
+    );
+}
+
+/* GLsync glFenceSync ( GLenum condition, GLbitfield flags ) */
+static jlong
+android_glFenceSync__II
+  (JNIEnv *_env, jobject _this, jint condition, jint flags) {
+    GLsync _returnValue;
+    _returnValue = glFenceSync(
+        (GLenum)condition,
+        (GLbitfield)flags
+    );
+    return (jlong)_returnValue;
+}
+
+/* GLboolean glIsSync ( GLsync sync ) */
+static jboolean
+android_glIsSync__J
+  (JNIEnv *_env, jobject _this, jlong sync) {
+    GLboolean _returnValue;
+    _returnValue = glIsSync(
+        (GLsync)sync
+    );
+    return (jboolean)_returnValue;
+}
+
+/* void glDeleteSync ( GLsync sync ) */
+static void
+android_glDeleteSync__J
+  (JNIEnv *_env, jobject _this, jlong sync) {
+    glDeleteSync(
+        (GLsync)sync
+    );
+}
+
+/* GLenum glClientWaitSync ( GLsync sync, GLbitfield flags, GLuint64 timeout ) */
+static jint
+android_glClientWaitSync__JIJ
+  (JNIEnv *_env, jobject _this, jlong sync, jint flags, jlong timeout) {
+    GLenum _returnValue;
+    _returnValue = glClientWaitSync(
+        (GLsync)sync,
+        (GLbitfield)flags,
+        (GLuint64)timeout
+    );
+    return (jint)_returnValue;
+}
+
+/* void glWaitSync ( GLsync sync, GLbitfield flags, GLuint64 timeout ) */
+static void
+android_glWaitSync__JIJ
+  (JNIEnv *_env, jobject _this, jlong sync, jint flags, jlong timeout) {
+    glWaitSync(
+        (GLsync)sync,
+        (GLbitfield)flags,
+        (GLuint64)timeout
+    );
+}
+
+/* void glGetInteger64v ( GLenum pname, GLint64 *params ) */
+static void
+android_glGetInteger64v__I_3JI
+  (JNIEnv *_env, jobject _this, jint pname, jlongArray params_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLint64 *params_base = (GLint64 *) 0;
+    jint _remaining;
+    GLint64 *params = (GLint64 *) 0;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(params_ref) - offset;
+    params_base = (GLint64 *)
+        _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+    params = params_base + offset;
+
+    glGetInteger64v(
+        (GLenum)pname,
+        (GLint64 *)params
+    );
+
+exit:
+    if (params_base) {
+        _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetInteger64v ( GLenum pname, GLint64 *params ) */
+static void
+android_glGetInteger64v__ILjava_nio_LongBuffer_2
+  (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLint64 *params = (GLint64 *) 0;
+
+    params = (GLint64 *)getPointer(_env, params_buf, &_array, &_remaining, &_bufferOffset);
+    if (params == NULL) {
+        char * _paramsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        params = (GLint64 *) (_paramsBase + _bufferOffset);
+    }
+    glGetInteger64v(
+        (GLenum)pname,
+        (GLint64 *)params
+    );
+    if (_array) {
+        releasePointer(_env, _array, params, JNI_TRUE);
+    }
+}
+
+/* void glGetSynciv ( GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values ) */
+static void
+android_glGetSynciv__JII_3II_3II
+  (JNIEnv *_env, jobject _this, jlong sync, jint pname, jint bufSize, jintArray length_ref, jint lengthOffset, jintArray values_ref, jint valuesOffset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLsizei *length_base = (GLsizei *) 0;
+    jint _lengthRemaining;
+    GLsizei *length = (GLsizei *) 0;
+    GLint *values_base = (GLint *) 0;
+    jint _valuesRemaining;
+    GLint *values = (GLint *) 0;
+
+    if (!length_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "length == null";
+        goto exit;
+    }
+    if (lengthOffset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "lengthOffset < 0";
+        goto exit;
+    }
+    _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset;
+    length_base = (GLsizei *)
+        _env->GetPrimitiveArrayCritical(length_ref, (jboolean *)0);
+    length = length_base + lengthOffset;
+
+    if (!values_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "values == null";
+        goto exit;
+    }
+    if (valuesOffset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "valuesOffset < 0";
+        goto exit;
+    }
+    _valuesRemaining = _env->GetArrayLength(values_ref) - valuesOffset;
+    values_base = (GLint *)
+        _env->GetPrimitiveArrayCritical(values_ref, (jboolean *)0);
+    values = values_base + valuesOffset;
+
+    glGetSynciv(
+        (GLsync)sync,
+        (GLenum)pname,
+        (GLsizei)bufSize,
+        (GLsizei *)length,
+        (GLint *)values
+    );
+
+exit:
+    if (values_base) {
+        _env->ReleasePrimitiveArrayCritical(values_ref, values_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (length_base) {
+        _env->ReleasePrimitiveArrayCritical(length_ref, length_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetSynciv ( GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values ) */
+static void
+android_glGetSynciv__JIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jlong sync, jint pname, jint bufSize, jobject length_buf, jobject values_buf) {
+    jarray _lengthArray = (jarray) 0;
+    jint _lengthBufferOffset = (jint) 0;
+    jarray _valuesArray = (jarray) 0;
+    jint _valuesBufferOffset = (jint) 0;
+    jint _lengthRemaining;
+    GLsizei *length = (GLsizei *) 0;
+    jint _valuesRemaining;
+    GLint *values = (GLint *) 0;
+
+    length = (GLsizei *)getPointer(_env, length_buf, &_lengthArray, &_lengthRemaining, &_lengthBufferOffset);
+    values = (GLint *)getPointer(_env, values_buf, &_valuesArray, &_valuesRemaining, &_valuesBufferOffset);
+    if (length == NULL) {
+        char * _lengthBase = (char *)_env->GetPrimitiveArrayCritical(_lengthArray, (jboolean *) 0);
+        length = (GLsizei *) (_lengthBase + _lengthBufferOffset);
+    }
+    if (values == NULL) {
+        char * _valuesBase = (char *)_env->GetPrimitiveArrayCritical(_valuesArray, (jboolean *) 0);
+        values = (GLint *) (_valuesBase + _valuesBufferOffset);
+    }
+    glGetSynciv(
+        (GLsync)sync,
+        (GLenum)pname,
+        (GLsizei)bufSize,
+        (GLsizei *)length,
+        (GLint *)values
+    );
+    if (_valuesArray) {
+        releasePointer(_env, _valuesArray, values, JNI_TRUE);
+    }
+    if (_lengthArray) {
+        releasePointer(_env, _lengthArray, length, JNI_TRUE);
+    }
+}
+
+/* void glGetInteger64i_v ( GLenum target, GLuint index, GLint64 *data ) */
+static void
+android_glGetInteger64i_v__II_3JI
+  (JNIEnv *_env, jobject _this, jint target, jint index, jlongArray data_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLint64 *data_base = (GLint64 *) 0;
+    jint _remaining;
+    GLint64 *data = (GLint64 *) 0;
+
+    if (!data_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "data == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(data_ref) - offset;
+    data_base = (GLint64 *)
+        _env->GetPrimitiveArrayCritical(data_ref, (jboolean *)0);
+    data = data_base + offset;
+
+    glGetInteger64i_v(
+        (GLenum)target,
+        (GLuint)index,
+        (GLint64 *)data
+    );
+
+exit:
+    if (data_base) {
+        _env->ReleasePrimitiveArrayCritical(data_ref, data_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetInteger64i_v ( GLenum target, GLuint index, GLint64 *data ) */
+static void
+android_glGetInteger64i_v__IILjava_nio_LongBuffer_2
+  (JNIEnv *_env, jobject _this, jint target, jint index, jobject data_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLint64 *data = (GLint64 *) 0;
+
+    data = (GLint64 *)getPointer(_env, data_buf, &_array, &_remaining, &_bufferOffset);
+    if (data == NULL) {
+        char * _dataBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        data = (GLint64 *) (_dataBase + _bufferOffset);
+    }
+    glGetInteger64i_v(
+        (GLenum)target,
+        (GLuint)index,
+        (GLint64 *)data
+    );
+    if (_array) {
+        releasePointer(_env, _array, data, JNI_TRUE);
+    }
+}
+
+/* void glGetBufferParameteri64v ( GLenum target, GLenum pname, GLint64 *params ) */
+static void
+android_glGetBufferParameteri64v__II_3JI
+  (JNIEnv *_env, jobject _this, jint target, jint pname, jlongArray params_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLint64 *params_base = (GLint64 *) 0;
+    jint _remaining;
+    GLint64 *params = (GLint64 *) 0;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(params_ref) - offset;
+    params_base = (GLint64 *)
+        _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+    params = params_base + offset;
+
+    glGetBufferParameteri64v(
+        (GLenum)target,
+        (GLenum)pname,
+        (GLint64 *)params
+    );
+
+exit:
+    if (params_base) {
+        _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetBufferParameteri64v ( GLenum target, GLenum pname, GLint64 *params ) */
+static void
+android_glGetBufferParameteri64v__IILjava_nio_LongBuffer_2
+  (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLint64 *params = (GLint64 *) 0;
+
+    params = (GLint64 *)getPointer(_env, params_buf, &_array, &_remaining, &_bufferOffset);
+    if (params == NULL) {
+        char * _paramsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        params = (GLint64 *) (_paramsBase + _bufferOffset);
+    }
+    glGetBufferParameteri64v(
+        (GLenum)target,
+        (GLenum)pname,
+        (GLint64 *)params
+    );
+    if (_array) {
+        releasePointer(_env, _array, params, JNI_TRUE);
+    }
+}
+
+/* void glGenSamplers ( GLsizei count, GLuint *samplers ) */
+static void
+android_glGenSamplers__I_3II
+  (JNIEnv *_env, jobject _this, jint count, jintArray samplers_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *samplers_base = (GLuint *) 0;
+    jint _remaining;
+    GLuint *samplers = (GLuint *) 0;
+
+    if (!samplers_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "samplers == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(samplers_ref) - offset;
+    samplers_base = (GLuint *)
+        _env->GetPrimitiveArrayCritical(samplers_ref, (jboolean *)0);
+    samplers = samplers_base + offset;
+
+    glGenSamplers(
+        (GLsizei)count,
+        (GLuint *)samplers
+    );
+
+exit:
+    if (samplers_base) {
+        _env->ReleasePrimitiveArrayCritical(samplers_ref, samplers_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGenSamplers ( GLsizei count, GLuint *samplers ) */
+static void
+android_glGenSamplers__ILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint count, jobject samplers_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLuint *samplers = (GLuint *) 0;
+
+    samplers = (GLuint *)getPointer(_env, samplers_buf, &_array, &_remaining, &_bufferOffset);
+    if (samplers == NULL) {
+        char * _samplersBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        samplers = (GLuint *) (_samplersBase + _bufferOffset);
+    }
+    glGenSamplers(
+        (GLsizei)count,
+        (GLuint *)samplers
+    );
+    if (_array) {
+        releasePointer(_env, _array, samplers, JNI_TRUE);
+    }
+}
+
+/* void glDeleteSamplers ( GLsizei count, const GLuint *samplers ) */
+static void
+android_glDeleteSamplers__I_3II
+  (JNIEnv *_env, jobject _this, jint count, jintArray samplers_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *samplers_base = (GLuint *) 0;
+    jint _remaining;
+    GLuint *samplers = (GLuint *) 0;
+
+    if (!samplers_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "samplers == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(samplers_ref) - offset;
+    samplers_base = (GLuint *)
+        _env->GetPrimitiveArrayCritical(samplers_ref, (jboolean *)0);
+    samplers = samplers_base + offset;
+
+    glDeleteSamplers(
+        (GLsizei)count,
+        (GLuint *)samplers
+    );
+
+exit:
+    if (samplers_base) {
+        _env->ReleasePrimitiveArrayCritical(samplers_ref, samplers_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glDeleteSamplers ( GLsizei count, const GLuint *samplers ) */
+static void
+android_glDeleteSamplers__ILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint count, jobject samplers_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLuint *samplers = (GLuint *) 0;
+
+    samplers = (GLuint *)getPointer(_env, samplers_buf, &_array, &_remaining, &_bufferOffset);
+    if (samplers == NULL) {
+        char * _samplersBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        samplers = (GLuint *) (_samplersBase + _bufferOffset);
+    }
+    glDeleteSamplers(
+        (GLsizei)count,
+        (GLuint *)samplers
+    );
+    if (_array) {
+        releasePointer(_env, _array, samplers, JNI_FALSE);
+    }
+}
+
+/* GLboolean glIsSampler ( GLuint sampler ) */
+static jboolean
+android_glIsSampler__I
+  (JNIEnv *_env, jobject _this, jint sampler) {
+    GLboolean _returnValue;
+    _returnValue = glIsSampler(
+        (GLuint)sampler
+    );
+    return (jboolean)_returnValue;
+}
+
+/* void glBindSampler ( GLuint unit, GLuint sampler ) */
+static void
+android_glBindSampler__II
+  (JNIEnv *_env, jobject _this, jint unit, jint sampler) {
+    glBindSampler(
+        (GLuint)unit,
+        (GLuint)sampler
+    );
+}
+
+/* void glSamplerParameteri ( GLuint sampler, GLenum pname, GLint param ) */
+static void
+android_glSamplerParameteri__III
+  (JNIEnv *_env, jobject _this, jint sampler, jint pname, jint param) {
+    glSamplerParameteri(
+        (GLuint)sampler,
+        (GLenum)pname,
+        (GLint)param
+    );
+}
+
+/* void glSamplerParameteriv ( GLuint sampler, GLenum pname, const GLint *param ) */
+static void
+android_glSamplerParameteriv__II_3II
+  (JNIEnv *_env, jobject _this, jint sampler, jint pname, jintArray param_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLint *param_base = (GLint *) 0;
+    jint _remaining;
+    GLint *param = (GLint *) 0;
+
+    if (!param_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "param == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(param_ref) - offset;
+    param_base = (GLint *)
+        _env->GetPrimitiveArrayCritical(param_ref, (jboolean *)0);
+    param = param_base + offset;
+
+    glSamplerParameteriv(
+        (GLuint)sampler,
+        (GLenum)pname,
+        (GLint *)param
+    );
+
+exit:
+    if (param_base) {
+        _env->ReleasePrimitiveArrayCritical(param_ref, param_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glSamplerParameteriv ( GLuint sampler, GLenum pname, const GLint *param ) */
+static void
+android_glSamplerParameteriv__IILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint sampler, jint pname, jobject param_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLint *param = (GLint *) 0;
+
+    param = (GLint *)getPointer(_env, param_buf, &_array, &_remaining, &_bufferOffset);
+    if (param == NULL) {
+        char * _paramBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        param = (GLint *) (_paramBase + _bufferOffset);
+    }
+    glSamplerParameteriv(
+        (GLuint)sampler,
+        (GLenum)pname,
+        (GLint *)param
+    );
+    if (_array) {
+        releasePointer(_env, _array, param, JNI_FALSE);
+    }
+}
+
+/* void glSamplerParameterf ( GLuint sampler, GLenum pname, GLfloat param ) */
+static void
+android_glSamplerParameterf__IIF
+  (JNIEnv *_env, jobject _this, jint sampler, jint pname, jfloat param) {
+    glSamplerParameterf(
+        (GLuint)sampler,
+        (GLenum)pname,
+        (GLfloat)param
+    );
+}
+
+/* void glSamplerParameterfv ( GLuint sampler, GLenum pname, const GLfloat *param ) */
+static void
+android_glSamplerParameterfv__II_3FI
+  (JNIEnv *_env, jobject _this, jint sampler, jint pname, jfloatArray param_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLfloat *param_base = (GLfloat *) 0;
+    jint _remaining;
+    GLfloat *param = (GLfloat *) 0;
+
+    if (!param_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "param == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(param_ref) - offset;
+    param_base = (GLfloat *)
+        _env->GetPrimitiveArrayCritical(param_ref, (jboolean *)0);
+    param = param_base + offset;
+
+    glSamplerParameterfv(
+        (GLuint)sampler,
+        (GLenum)pname,
+        (GLfloat *)param
+    );
+
+exit:
+    if (param_base) {
+        _env->ReleasePrimitiveArrayCritical(param_ref, param_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glSamplerParameterfv ( GLuint sampler, GLenum pname, const GLfloat *param ) */
+static void
+android_glSamplerParameterfv__IILjava_nio_FloatBuffer_2
+  (JNIEnv *_env, jobject _this, jint sampler, jint pname, jobject param_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLfloat *param = (GLfloat *) 0;
+
+    param = (GLfloat *)getPointer(_env, param_buf, &_array, &_remaining, &_bufferOffset);
+    if (param == NULL) {
+        char * _paramBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        param = (GLfloat *) (_paramBase + _bufferOffset);
+    }
+    glSamplerParameterfv(
+        (GLuint)sampler,
+        (GLenum)pname,
+        (GLfloat *)param
+    );
+    if (_array) {
+        releasePointer(_env, _array, param, JNI_FALSE);
+    }
+}
+
+/* void glGetSamplerParameteriv ( GLuint sampler, GLenum pname, GLint *params ) */
+static void
+android_glGetSamplerParameteriv__II_3II
+  (JNIEnv *_env, jobject _this, jint sampler, jint pname, jintArray params_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLint *params_base = (GLint *) 0;
+    jint _remaining;
+    GLint *params = (GLint *) 0;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(params_ref) - offset;
+    params_base = (GLint *)
+        _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+    params = params_base + offset;
+
+    glGetSamplerParameteriv(
+        (GLuint)sampler,
+        (GLenum)pname,
+        (GLint *)params
+    );
+
+exit:
+    if (params_base) {
+        _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetSamplerParameteriv ( GLuint sampler, GLenum pname, GLint *params ) */
+static void
+android_glGetSamplerParameteriv__IILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint sampler, jint pname, jobject params_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLint *params = (GLint *) 0;
+
+    params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining, &_bufferOffset);
+    if (params == NULL) {
+        char * _paramsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        params = (GLint *) (_paramsBase + _bufferOffset);
+    }
+    glGetSamplerParameteriv(
+        (GLuint)sampler,
+        (GLenum)pname,
+        (GLint *)params
+    );
+    if (_array) {
+        releasePointer(_env, _array, params, JNI_TRUE);
+    }
+}
+
+/* void glGetSamplerParameterfv ( GLuint sampler, GLenum pname, GLfloat *params ) */
+static void
+android_glGetSamplerParameterfv__II_3FI
+  (JNIEnv *_env, jobject _this, jint sampler, jint pname, jfloatArray params_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLfloat *params_base = (GLfloat *) 0;
+    jint _remaining;
+    GLfloat *params = (GLfloat *) 0;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(params_ref) - offset;
+    params_base = (GLfloat *)
+        _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+    params = params_base + offset;
+
+    glGetSamplerParameterfv(
+        (GLuint)sampler,
+        (GLenum)pname,
+        (GLfloat *)params
+    );
+
+exit:
+    if (params_base) {
+        _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetSamplerParameterfv ( GLuint sampler, GLenum pname, GLfloat *params ) */
+static void
+android_glGetSamplerParameterfv__IILjava_nio_FloatBuffer_2
+  (JNIEnv *_env, jobject _this, jint sampler, jint pname, jobject params_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLfloat *params = (GLfloat *) 0;
+
+    params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining, &_bufferOffset);
+    if (params == NULL) {
+        char * _paramsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        params = (GLfloat *) (_paramsBase + _bufferOffset);
+    }
+    glGetSamplerParameterfv(
+        (GLuint)sampler,
+        (GLenum)pname,
+        (GLfloat *)params
+    );
+    if (_array) {
+        releasePointer(_env, _array, params, JNI_TRUE);
+    }
+}
+
+/* void glVertexAttribDivisor ( GLuint index, GLuint divisor ) */
+static void
+android_glVertexAttribDivisor__II
+  (JNIEnv *_env, jobject _this, jint index, jint divisor) {
+    glVertexAttribDivisor(
+        (GLuint)index,
+        (GLuint)divisor
+    );
+}
+
+/* void glBindTransformFeedback ( GLenum target, GLuint id ) */
+static void
+android_glBindTransformFeedback__II
+  (JNIEnv *_env, jobject _this, jint target, jint id) {
+    glBindTransformFeedback(
+        (GLenum)target,
+        (GLuint)id
+    );
+}
+
+/* void glDeleteTransformFeedbacks ( GLsizei n, const GLuint *ids ) */
+static void
+android_glDeleteTransformFeedbacks__I_3II
+  (JNIEnv *_env, jobject _this, jint n, jintArray ids_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *ids_base = (GLuint *) 0;
+    jint _remaining;
+    GLuint *ids = (GLuint *) 0;
+
+    if (!ids_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "ids == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(ids_ref) - offset;
+    ids_base = (GLuint *)
+        _env->GetPrimitiveArrayCritical(ids_ref, (jboolean *)0);
+    ids = ids_base + offset;
+
+    glDeleteTransformFeedbacks(
+        (GLsizei)n,
+        (GLuint *)ids
+    );
+
+exit:
+    if (ids_base) {
+        _env->ReleasePrimitiveArrayCritical(ids_ref, ids_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glDeleteTransformFeedbacks ( GLsizei n, const GLuint *ids ) */
+static void
+android_glDeleteTransformFeedbacks__ILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint n, jobject ids_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLuint *ids = (GLuint *) 0;
+
+    ids = (GLuint *)getPointer(_env, ids_buf, &_array, &_remaining, &_bufferOffset);
+    if (ids == NULL) {
+        char * _idsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        ids = (GLuint *) (_idsBase + _bufferOffset);
+    }
+    glDeleteTransformFeedbacks(
+        (GLsizei)n,
+        (GLuint *)ids
+    );
+    if (_array) {
+        releasePointer(_env, _array, ids, JNI_FALSE);
+    }
+}
+
+/* void glGenTransformFeedbacks ( GLsizei n, GLuint *ids ) */
+static void
+android_glGenTransformFeedbacks__I_3II
+  (JNIEnv *_env, jobject _this, jint n, jintArray ids_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *ids_base = (GLuint *) 0;
+    jint _remaining;
+    GLuint *ids = (GLuint *) 0;
+
+    if (!ids_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "ids == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(ids_ref) - offset;
+    ids_base = (GLuint *)
+        _env->GetPrimitiveArrayCritical(ids_ref, (jboolean *)0);
+    ids = ids_base + offset;
+
+    glGenTransformFeedbacks(
+        (GLsizei)n,
+        (GLuint *)ids
+    );
+
+exit:
+    if (ids_base) {
+        _env->ReleasePrimitiveArrayCritical(ids_ref, ids_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGenTransformFeedbacks ( GLsizei n, GLuint *ids ) */
+static void
+android_glGenTransformFeedbacks__ILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint n, jobject ids_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLuint *ids = (GLuint *) 0;
+
+    ids = (GLuint *)getPointer(_env, ids_buf, &_array, &_remaining, &_bufferOffset);
+    if (ids == NULL) {
+        char * _idsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        ids = (GLuint *) (_idsBase + _bufferOffset);
+    }
+    glGenTransformFeedbacks(
+        (GLsizei)n,
+        (GLuint *)ids
+    );
+    if (_array) {
+        releasePointer(_env, _array, ids, JNI_TRUE);
+    }
+}
+
+/* GLboolean glIsTransformFeedback ( GLuint id ) */
+static jboolean
+android_glIsTransformFeedback__I
+  (JNIEnv *_env, jobject _this, jint id) {
+    GLboolean _returnValue;
+    _returnValue = glIsTransformFeedback(
+        (GLuint)id
+    );
+    return (jboolean)_returnValue;
+}
+
+/* void glPauseTransformFeedback ( void ) */
+static void
+android_glPauseTransformFeedback__
+  (JNIEnv *_env, jobject _this) {
+    glPauseTransformFeedback();
+}
+
+/* void glResumeTransformFeedback ( void ) */
+static void
+android_glResumeTransformFeedback__
+  (JNIEnv *_env, jobject _this) {
+    glResumeTransformFeedback();
+}
+
+/* void glGetProgramBinary ( GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary ) */
+static void
+android_glGetProgramBinary__II_3II_3IILjava_nio_Buffer_2
+  (JNIEnv *_env, jobject _this, jint program, jint bufSize, jintArray length_ref, jint lengthOffset, jintArray binaryFormat_ref, jint binaryFormatOffset, jobject binary_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    GLsizei *length_base = (GLsizei *) 0;
+    jint _lengthRemaining;
+    GLsizei *length = (GLsizei *) 0;
+    GLenum *binaryFormat_base = (GLenum *) 0;
+    jint _binaryFormatRemaining;
+    GLenum *binaryFormat = (GLenum *) 0;
+    jint _binaryRemaining;
+    GLvoid *binary = (GLvoid *) 0;
+
+    if (!length_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "length == null";
+        goto exit;
+    }
+    if (lengthOffset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "lengthOffset < 0";
+        goto exit;
+    }
+    _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset;
+    length_base = (GLsizei *)
+        _env->GetPrimitiveArrayCritical(length_ref, (jboolean *)0);
+    length = length_base + lengthOffset;
+
+    if (!binaryFormat_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "binaryFormat == null";
+        goto exit;
+    }
+    if (binaryFormatOffset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "binaryFormatOffset < 0";
+        goto exit;
+    }
+    _binaryFormatRemaining = _env->GetArrayLength(binaryFormat_ref) - binaryFormatOffset;
+    binaryFormat_base = (GLenum *)
+        _env->GetPrimitiveArrayCritical(binaryFormat_ref, (jboolean *)0);
+    binaryFormat = binaryFormat_base + binaryFormatOffset;
+
+    binary = (GLvoid *)getPointer(_env, binary_buf, &_array, &_binaryRemaining, &_bufferOffset);
+    if (binary == NULL) {
+        char * _binaryBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        binary = (GLvoid *) (_binaryBase + _bufferOffset);
+    }
+    glGetProgramBinary(
+        (GLuint)program,
+        (GLsizei)bufSize,
+        (GLsizei *)length,
+        (GLenum *)binaryFormat,
+        (GLvoid *)binary
+    );
+
+exit:
+    if (_array) {
+        releasePointer(_env, _array, binary, _exception ? JNI_FALSE : JNI_TRUE);
+    }
+    if (binaryFormat_base) {
+        _env->ReleasePrimitiveArrayCritical(binaryFormat_ref, binaryFormat_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (length_base) {
+        _env->ReleasePrimitiveArrayCritical(length_ref, length_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetProgramBinary ( GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary ) */
+static void
+android_glGetProgramBinary__IILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_Buffer_2
+  (JNIEnv *_env, jobject _this, jint program, jint bufSize, jobject length_buf, jobject binaryFormat_buf, jobject binary_buf) {
+    jarray _lengthArray = (jarray) 0;
+    jint _lengthBufferOffset = (jint) 0;
+    jarray _binaryFormatArray = (jarray) 0;
+    jint _binaryFormatBufferOffset = (jint) 0;
+    jarray _binaryArray = (jarray) 0;
+    jint _binaryBufferOffset = (jint) 0;
+    jint _lengthRemaining;
+    GLsizei *length = (GLsizei *) 0;
+    jint _binaryFormatRemaining;
+    GLenum *binaryFormat = (GLenum *) 0;
+    jint _binaryRemaining;
+    GLvoid *binary = (GLvoid *) 0;
+
+    length = (GLsizei *)getPointer(_env, length_buf, &_lengthArray, &_lengthRemaining, &_lengthBufferOffset);
+    binaryFormat = (GLenum *)getPointer(_env, binaryFormat_buf, &_binaryFormatArray, &_binaryFormatRemaining, &_binaryFormatBufferOffset);
+    binary = (GLvoid *)getPointer(_env, binary_buf, &_binaryArray, &_binaryRemaining, &_binaryBufferOffset);
+    if (length == NULL) {
+        char * _lengthBase = (char *)_env->GetPrimitiveArrayCritical(_lengthArray, (jboolean *) 0);
+        length = (GLsizei *) (_lengthBase + _lengthBufferOffset);
+    }
+    if (binaryFormat == NULL) {
+        char * _binaryFormatBase = (char *)_env->GetPrimitiveArrayCritical(_binaryFormatArray, (jboolean *) 0);
+        binaryFormat = (GLenum *) (_binaryFormatBase + _binaryFormatBufferOffset);
+    }
+    if (binary == NULL) {
+        char * _binaryBase = (char *)_env->GetPrimitiveArrayCritical(_binaryArray, (jboolean *) 0);
+        binary = (GLvoid *) (_binaryBase + _binaryBufferOffset);
+    }
+    glGetProgramBinary(
+        (GLuint)program,
+        (GLsizei)bufSize,
+        (GLsizei *)length,
+        (GLenum *)binaryFormat,
+        (GLvoid *)binary
+    );
+    if (_binaryArray) {
+        releasePointer(_env, _binaryArray, binary, JNI_TRUE);
+    }
+    if (_binaryFormatArray) {
+        releasePointer(_env, _binaryFormatArray, binaryFormat, JNI_TRUE);
+    }
+    if (_lengthArray) {
+        releasePointer(_env, _lengthArray, length, JNI_TRUE);
+    }
+}
+
+/* void glProgramBinary ( GLuint program, GLenum binaryFormat, const GLvoid *binary, GLsizei length ) */
+static void
+android_glProgramBinary__IILjava_nio_Buffer_2I
+  (JNIEnv *_env, jobject _this, jint program, jint binaryFormat, jobject binary_buf, jint length) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLvoid *binary = (GLvoid *) 0;
+
+    binary = (GLvoid *)getPointer(_env, binary_buf, &_array, &_remaining, &_bufferOffset);
+    if (binary == NULL) {
+        char * _binaryBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        binary = (GLvoid *) (_binaryBase + _bufferOffset);
+    }
+    glProgramBinary(
+        (GLuint)program,
+        (GLenum)binaryFormat,
+        (GLvoid *)binary,
+        (GLsizei)length
+    );
+    if (_array) {
+        releasePointer(_env, _array, binary, JNI_FALSE);
+    }
+}
+
+/* void glProgramParameteri ( GLuint program, GLenum pname, GLint value ) */
+static void
+android_glProgramParameteri__III
+  (JNIEnv *_env, jobject _this, jint program, jint pname, jint value) {
+    glProgramParameteri(
+        (GLuint)program,
+        (GLenum)pname,
+        (GLint)value
+    );
+}
+
+/* void glInvalidateFramebuffer ( GLenum target, GLsizei numAttachments, const GLenum *attachments ) */
+static void
+android_glInvalidateFramebuffer__II_3II
+  (JNIEnv *_env, jobject _this, jint target, jint numAttachments, jintArray attachments_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLenum *attachments_base = (GLenum *) 0;
+    jint _remaining;
+    GLenum *attachments = (GLenum *) 0;
+
+    if (!attachments_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "attachments == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(attachments_ref) - offset;
+    attachments_base = (GLenum *)
+        _env->GetPrimitiveArrayCritical(attachments_ref, (jboolean *)0);
+    attachments = attachments_base + offset;
+
+    glInvalidateFramebuffer(
+        (GLenum)target,
+        (GLsizei)numAttachments,
+        (GLenum *)attachments
+    );
+
+exit:
+    if (attachments_base) {
+        _env->ReleasePrimitiveArrayCritical(attachments_ref, attachments_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glInvalidateFramebuffer ( GLenum target, GLsizei numAttachments, const GLenum *attachments ) */
+static void
+android_glInvalidateFramebuffer__IILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint target, jint numAttachments, jobject attachments_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLenum *attachments = (GLenum *) 0;
+
+    attachments = (GLenum *)getPointer(_env, attachments_buf, &_array, &_remaining, &_bufferOffset);
+    if (attachments == NULL) {
+        char * _attachmentsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        attachments = (GLenum *) (_attachmentsBase + _bufferOffset);
+    }
+    glInvalidateFramebuffer(
+        (GLenum)target,
+        (GLsizei)numAttachments,
+        (GLenum *)attachments
+    );
+    if (_array) {
+        releasePointer(_env, _array, attachments, JNI_FALSE);
+    }
+}
+
+/* void glInvalidateSubFramebuffer ( GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height ) */
+static void
+android_glInvalidateSubFramebuffer__II_3IIIIII
+  (JNIEnv *_env, jobject _this, jint target, jint numAttachments, jintArray attachments_ref, jint offset, jint x, jint y, jint width, jint height) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLenum *attachments_base = (GLenum *) 0;
+    jint _remaining;
+    GLenum *attachments = (GLenum *) 0;
+
+    if (!attachments_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "attachments == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(attachments_ref) - offset;
+    attachments_base = (GLenum *)
+        _env->GetPrimitiveArrayCritical(attachments_ref, (jboolean *)0);
+    attachments = attachments_base + offset;
+
+    glInvalidateSubFramebuffer(
+        (GLenum)target,
+        (GLsizei)numAttachments,
+        (GLenum *)attachments,
+        (GLint)x,
+        (GLint)y,
+        (GLsizei)width,
+        (GLsizei)height
+    );
+
+exit:
+    if (attachments_base) {
+        _env->ReleasePrimitiveArrayCritical(attachments_ref, attachments_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glInvalidateSubFramebuffer ( GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height ) */
+static void
+android_glInvalidateSubFramebuffer__IILjava_nio_IntBuffer_2IIII
+  (JNIEnv *_env, jobject _this, jint target, jint numAttachments, jobject attachments_buf, jint x, jint y, jint width, jint height) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLenum *attachments = (GLenum *) 0;
+
+    attachments = (GLenum *)getPointer(_env, attachments_buf, &_array, &_remaining, &_bufferOffset);
+    if (attachments == NULL) {
+        char * _attachmentsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        attachments = (GLenum *) (_attachmentsBase + _bufferOffset);
+    }
+    glInvalidateSubFramebuffer(
+        (GLenum)target,
+        (GLsizei)numAttachments,
+        (GLenum *)attachments,
+        (GLint)x,
+        (GLint)y,
+        (GLsizei)width,
+        (GLsizei)height
+    );
+    if (_array) {
+        releasePointer(_env, _array, attachments, JNI_FALSE);
+    }
+}
+
+/* void glTexStorage2D ( GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height ) */
+static void
+android_glTexStorage2D__IIIII
+  (JNIEnv *_env, jobject _this, jint target, jint levels, jint internalformat, jint width, jint height) {
+    glTexStorage2D(
+        (GLenum)target,
+        (GLsizei)levels,
+        (GLenum)internalformat,
+        (GLsizei)width,
+        (GLsizei)height
+    );
+}
+
+/* void glTexStorage3D ( GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth ) */
+static void
+android_glTexStorage3D__IIIIII
+  (JNIEnv *_env, jobject _this, jint target, jint levels, jint internalformat, jint width, jint height, jint depth) {
+    glTexStorage3D(
+        (GLenum)target,
+        (GLsizei)levels,
+        (GLenum)internalformat,
+        (GLsizei)width,
+        (GLsizei)height,
+        (GLsizei)depth
+    );
+}
+
+/* void glGetInternalformativ ( GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params ) */
+static void
+android_glGetInternalformativ__IIII_3II
+  (JNIEnv *_env, jobject _this, jint target, jint internalformat, jint pname, jint bufSize, jintArray params_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLint *params_base = (GLint *) 0;
+    jint _remaining;
+    GLint *params = (GLint *) 0;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(params_ref) - offset;
+    params_base = (GLint *)
+        _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+    params = params_base + offset;
+
+    glGetInternalformativ(
+        (GLenum)target,
+        (GLenum)internalformat,
+        (GLenum)pname,
+        (GLsizei)bufSize,
+        (GLint *)params
+    );
+
+exit:
+    if (params_base) {
+        _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetInternalformativ ( GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params ) */
+static void
+android_glGetInternalformativ__IIIILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint target, jint internalformat, jint pname, jint bufSize, jobject params_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLint *params = (GLint *) 0;
+
+    params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining, &_bufferOffset);
+    if (params == NULL) {
+        char * _paramsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        params = (GLint *) (_paramsBase + _bufferOffset);
+    }
+    glGetInternalformativ(
+        (GLenum)target,
+        (GLenum)internalformat,
+        (GLenum)pname,
+        (GLsizei)bufSize,
+        (GLint *)params
+    );
+    if (_array) {
+        releasePointer(_env, _array, params, JNI_TRUE);
+    }
+}
+
+static const char *classPathName = "android/opengl/GLES30";
+
+static JNINativeMethod methods[] = {
+{"_nativeClassInit", "()V", (void*)nativeClassInit },
+{"glReadBuffer", "(I)V", (void *) android_glReadBuffer__I },
+{"glDrawRangeElements", "(IIIIILjava/nio/Buffer;)V", (void *) android_glDrawRangeElements__IIIIILjava_nio_Buffer_2 },
+{"glDrawRangeElements", "(IIIIII)V", (void *) android_glDrawRangeElements__IIIIII },
+{"glTexImage3D", "(IIIIIIIIILjava/nio/Buffer;)V", (void *) android_glTexImage3D__IIIIIIIIILjava_nio_Buffer_2 },
+{"glTexImage3D", "(IIIIIIIIII)V", (void *) android_glTexImage3D__IIIIIIIIII },
+{"glTexSubImage3D", "(IIIIIIIIIILjava/nio/Buffer;)V", (void *) android_glTexSubImage3D__IIIIIIIIIILjava_nio_Buffer_2 },
+{"glTexSubImage3D", "(IIIIIIIIIII)V", (void *) android_glTexSubImage3D__IIIIIIIIIII },
+{"glCopyTexSubImage3D", "(IIIIIIIII)V", (void *) android_glCopyTexSubImage3D__IIIIIIIII },
+{"glCompressedTexImage3D", "(IIIIIIIILjava/nio/Buffer;)V", (void *) android_glCompressedTexImage3D__IIIIIIIILjava_nio_Buffer_2 },
+{"glCompressedTexImage3D", "(IIIIIIIII)V", (void *) android_glCompressedTexImage3D__IIIIIIIII },
+{"glCompressedTexSubImage3D", "(IIIIIIIIIILjava/nio/Buffer;)V", (void *) android_glCompressedTexSubImage3D__IIIIIIIIIILjava_nio_Buffer_2 },
+{"glCompressedTexSubImage3D", "(IIIIIIIIIII)V", (void *) android_glCompressedTexSubImage3D__IIIIIIIIIII },
+{"glGenQueries", "(I[II)V", (void *) android_glGenQueries__I_3II },
+{"glGenQueries", "(ILjava/nio/IntBuffer;)V", (void *) android_glGenQueries__ILjava_nio_IntBuffer_2 },
+{"glDeleteQueries", "(I[II)V", (void *) android_glDeleteQueries__I_3II },
+{"glDeleteQueries", "(ILjava/nio/IntBuffer;)V", (void *) android_glDeleteQueries__ILjava_nio_IntBuffer_2 },
+{"glIsQuery", "(I)Z", (void *) android_glIsQuery__I },
+{"glBeginQuery", "(II)V", (void *) android_glBeginQuery__II },
+{"glEndQuery", "(I)V", (void *) android_glEndQuery__I },
+{"glGetQueryiv", "(II[II)V", (void *) android_glGetQueryiv__II_3II },
+{"glGetQueryiv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetQueryiv__IILjava_nio_IntBuffer_2 },
+{"glGetQueryObjectuiv", "(II[II)V", (void *) android_glGetQueryObjectuiv__II_3II },
+{"glGetQueryObjectuiv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetQueryObjectuiv__IILjava_nio_IntBuffer_2 },
+{"glUnmapBuffer", "(I)Z", (void *) android_glUnmapBuffer__I },
+{"glGetBufferPointerv", "(II)Ljava/nio/Buffer;", (void *) android_glGetBufferPointerv__II },
+{"glDrawBuffers", "(I[II)V", (void *) android_glDrawBuffers__I_3II },
+{"glDrawBuffers", "(ILjava/nio/IntBuffer;)V", (void *) android_glDrawBuffers__ILjava_nio_IntBuffer_2 },
+{"glUniformMatrix2x3fv", "(IIZ[FI)V", (void *) android_glUniformMatrix2x3fv__IIZ_3FI },
+{"glUniformMatrix2x3fv", "(IIZLjava/nio/FloatBuffer;)V", (void *) android_glUniformMatrix2x3fv__IIZLjava_nio_FloatBuffer_2 },
+{"glUniformMatrix3x2fv", "(IIZ[FI)V", (void *) android_glUniformMatrix3x2fv__IIZ_3FI },
+{"glUniformMatrix3x2fv", "(IIZLjava/nio/FloatBuffer;)V", (void *) android_glUniformMatrix3x2fv__IIZLjava_nio_FloatBuffer_2 },
+{"glUniformMatrix2x4fv", "(IIZ[FI)V", (void *) android_glUniformMatrix2x4fv__IIZ_3FI },
+{"glUniformMatrix2x4fv", "(IIZLjava/nio/FloatBuffer;)V", (void *) android_glUniformMatrix2x4fv__IIZLjava_nio_FloatBuffer_2 },
+{"glUniformMatrix4x2fv", "(IIZ[FI)V", (void *) android_glUniformMatrix4x2fv__IIZ_3FI },
+{"glUniformMatrix4x2fv", "(IIZLjava/nio/FloatBuffer;)V", (void *) android_glUniformMatrix4x2fv__IIZLjava_nio_FloatBuffer_2 },
+{"glUniformMatrix3x4fv", "(IIZ[FI)V", (void *) android_glUniformMatrix3x4fv__IIZ_3FI },
+{"glUniformMatrix3x4fv", "(IIZLjava/nio/FloatBuffer;)V", (void *) android_glUniformMatrix3x4fv__IIZLjava_nio_FloatBuffer_2 },
+{"glUniformMatrix4x3fv", "(IIZ[FI)V", (void *) android_glUniformMatrix4x3fv__IIZ_3FI },
+{"glUniformMatrix4x3fv", "(IIZLjava/nio/FloatBuffer;)V", (void *) android_glUniformMatrix4x3fv__IIZLjava_nio_FloatBuffer_2 },
+{"glBlitFramebuffer", "(IIIIIIIIII)V", (void *) android_glBlitFramebuffer__IIIIIIIIII },
+{"glRenderbufferStorageMultisample", "(IIIII)V", (void *) android_glRenderbufferStorageMultisample__IIIII },
+{"glFramebufferTextureLayer", "(IIIII)V", (void *) android_glFramebufferTextureLayer__IIIII },
+{"glMapBufferRange", "(IIII)Ljava/nio/Buffer;", (void *) android_glMapBufferRange__IIII },
+{"glFlushMappedBufferRange", "(III)V", (void *) android_glFlushMappedBufferRange__III },
+{"glBindVertexArray", "(I)V", (void *) android_glBindVertexArray__I },
+{"glDeleteVertexArrays", "(I[II)V", (void *) android_glDeleteVertexArrays__I_3II },
+{"glDeleteVertexArrays", "(ILjava/nio/IntBuffer;)V", (void *) android_glDeleteVertexArrays__ILjava_nio_IntBuffer_2 },
+{"glGenVertexArrays", "(I[II)V", (void *) android_glGenVertexArrays__I_3II },
+{"glGenVertexArrays", "(ILjava/nio/IntBuffer;)V", (void *) android_glGenVertexArrays__ILjava_nio_IntBuffer_2 },
+{"glIsVertexArray", "(I)Z", (void *) android_glIsVertexArray__I },
+{"glGetIntegeri_v", "(II[II)V", (void *) android_glGetIntegeri_v__II_3II },
+{"glGetIntegeri_v", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetIntegeri_v__IILjava_nio_IntBuffer_2 },
+{"glBeginTransformFeedback", "(I)V", (void *) android_glBeginTransformFeedback__I },
+{"glEndTransformFeedback", "()V", (void *) android_glEndTransformFeedback__ },
+{"glBindBufferRange", "(IIIII)V", (void *) android_glBindBufferRange__IIIII },
+{"glBindBufferBase", "(III)V", (void *) android_glBindBufferBase__III },
+{"glTransformFeedbackVaryings", "(I[Ljava/lang/String;I)V", (void *) android_glTransformFeedbackVaryings },
+{"glGetTransformFeedbackVarying", "(III[II[II[II[BI)V", (void *) android_glGetTransformFeedbackVarying__III_3II_3II_3II_3BI },
+{"glGetTransformFeedbackVarying", "(IIILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;B)V", (void *) android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B },
+{"glGetTransformFeedbackVarying", "(II[II[II)Ljava/lang/String;", (void *) android_glGetTransformFeedbackVarying1 },
+{"glGetTransformFeedbackVarying", "(IILjava/nio/IntBuffer;Ljava/nio/IntBuffer;)Ljava/lang/String;", (void *) android_glGetTransformFeedbackVarying2 },
+{"glVertexAttribIPointerBounds", "(IIIILjava/nio/Buffer;I)V", (void *) android_glVertexAttribIPointerBounds__IIIILjava_nio_Buffer_2I },
+{"glVertexAttribIPointer", "(IIIII)V", (void *) android_glVertexAttribIPointer__IIIII },
+{"glGetVertexAttribIiv", "(II[II)V", (void *) android_glGetVertexAttribIiv__II_3II },
+{"glGetVertexAttribIiv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetVertexAttribIiv__IILjava_nio_IntBuffer_2 },
+{"glGetVertexAttribIuiv", "(II[II)V", (void *) android_glGetVertexAttribIuiv__II_3II },
+{"glGetVertexAttribIuiv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetVertexAttribIuiv__IILjava_nio_IntBuffer_2 },
+{"glVertexAttribI4i", "(IIIII)V", (void *) android_glVertexAttribI4i__IIIII },
+{"glVertexAttribI4ui", "(IIIII)V", (void *) android_glVertexAttribI4ui__IIIII },
+{"glVertexAttribI4iv", "(I[II)V", (void *) android_glVertexAttribI4iv__I_3II },
+{"glVertexAttribI4iv", "(ILjava/nio/IntBuffer;)V", (void *) android_glVertexAttribI4iv__ILjava_nio_IntBuffer_2 },
+{"glVertexAttribI4uiv", "(I[II)V", (void *) android_glVertexAttribI4uiv__I_3II },
+{"glVertexAttribI4uiv", "(ILjava/nio/IntBuffer;)V", (void *) android_glVertexAttribI4uiv__ILjava_nio_IntBuffer_2 },
+{"glGetUniformuiv", "(II[II)V", (void *) android_glGetUniformuiv__II_3II },
+{"glGetUniformuiv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetUniformuiv__IILjava_nio_IntBuffer_2 },
+{"glGetFragDataLocation", "(ILjava/lang/String;)I", (void *) android_glGetFragDataLocation__ILjava_lang_String_2 },
+{"glUniform1ui", "(II)V", (void *) android_glUniform1ui__II },
+{"glUniform2ui", "(III)V", (void *) android_glUniform2ui__III },
+{"glUniform3ui", "(IIII)V", (void *) android_glUniform3ui__IIII },
+{"glUniform4ui", "(IIIII)V", (void *) android_glUniform4ui__IIIII },
+{"glUniform1uiv", "(II[II)V", (void *) android_glUniform1uiv__II_3II },
+{"glUniform1uiv", "(IILjava/nio/IntBuffer;)V", (void *) android_glUniform1uiv__IILjava_nio_IntBuffer_2 },
+{"glUniform2uiv", "(II[II)V", (void *) android_glUniform2uiv__II_3II },
+{"glUniform2uiv", "(IILjava/nio/IntBuffer;)V", (void *) android_glUniform2uiv__IILjava_nio_IntBuffer_2 },
+{"glUniform3uiv", "(II[II)V", (void *) android_glUniform3uiv__II_3II },
+{"glUniform3uiv", "(IILjava/nio/IntBuffer;)V", (void *) android_glUniform3uiv__IILjava_nio_IntBuffer_2 },
+{"glUniform4uiv", "(II[II)V", (void *) android_glUniform4uiv__II_3II },
+{"glUniform4uiv", "(IILjava/nio/IntBuffer;)V", (void *) android_glUniform4uiv__IILjava_nio_IntBuffer_2 },
+{"glClearBufferiv", "(II[II)V", (void *) android_glClearBufferiv__II_3II },
+{"glClearBufferiv", "(IILjava/nio/IntBuffer;)V", (void *) android_glClearBufferiv__IILjava_nio_IntBuffer_2 },
+{"glClearBufferuiv", "(II[II)V", (void *) android_glClearBufferuiv__II_3II },
+{"glClearBufferuiv", "(IILjava/nio/IntBuffer;)V", (void *) android_glClearBufferuiv__IILjava_nio_IntBuffer_2 },
+{"glClearBufferfv", "(II[FI)V", (void *) android_glClearBufferfv__II_3FI },
+{"glClearBufferfv", "(IILjava/nio/FloatBuffer;)V", (void *) android_glClearBufferfv__IILjava_nio_FloatBuffer_2 },
+{"glClearBufferfi", "(IIFI)V", (void *) android_glClearBufferfi__IIFI },
+{"glGetStringi", "(II)Ljava/lang/String;", (void *) android_glGetStringi__II },
+{"glCopyBufferSubData", "(IIIII)V", (void *) android_glCopyBufferSubData__IIIII },
+{"glGetUniformIndices", "(I[Ljava/lang/String;[II)V", (void *) android_glGetUniformIndices_array },
+{"glGetUniformIndices", "(I[Ljava/lang/String;[Ljava/nio/IntBuffer)V", (void *) android_glGetUniformIndices_buffer },
+{"glGetActiveUniformsiv", "(II[III[II)V", (void *) android_glGetActiveUniformsiv__II_3III_3II },
+{"glGetActiveUniformsiv", "(IILjava/nio/IntBuffer;ILjava/nio/IntBuffer;)V", (void *) android_glGetActiveUniformsiv__IILjava_nio_IntBuffer_2ILjava_nio_IntBuffer_2 },
+{"glGetUniformBlockIndex", "(ILjava/lang/String;)I", (void *) android_glGetUniformBlockIndex__ILjava_lang_String_2 },
+{"glGetActiveUniformBlockiv", "(III[II)V", (void *) android_glGetActiveUniformBlockiv__III_3II },
+{"glGetActiveUniformBlockiv", "(IIILjava/nio/IntBuffer;)V", (void *) android_glGetActiveUniformBlockiv__IIILjava_nio_IntBuffer_2 },
+{"glGetActiveUniformBlockName", "(III[II[BI)V", (void *) android_glGetActiveUniformBlockName_III_3II_3BI },
+{"glGetActiveUniformBlockName", "(IILjava/nio/Buffer;Ljava/nio/Buffer;)V", (void *) android_glGetActiveUniformBlockName_IILjava_nio_Buffer_2Ljava_nio_Buffer_2 },
+{"glGetActiveUniformBlockName", "(II)Ljava/lang/String;", (void *) android_glGetActiveUniformBlockName_II },
+{"glUniformBlockBinding", "(III)V", (void *) android_glUniformBlockBinding__III },
+{"glDrawArraysInstanced", "(IIII)V", (void *) android_glDrawArraysInstanced__IIII },
+{"glDrawElementsInstanced", "(IIILjava/nio/Buffer;I)V", (void *) android_glDrawElementsInstanced__IIILjava_nio_Buffer_2I },
+{"glDrawElementsInstanced", "(IIIII)V", (void *) android_glDrawElementsInstanced__IIIII },
+{"glFenceSync", "(II)J", (void *) android_glFenceSync__II },
+{"glIsSync", "(J)Z", (void *) android_glIsSync__J },
+{"glDeleteSync", "(J)V", (void *) android_glDeleteSync__J },
+{"glClientWaitSync", "(JIJ)I", (void *) android_glClientWaitSync__JIJ },
+{"glWaitSync", "(JIJ)V", (void *) android_glWaitSync__JIJ },
+{"glGetInteger64v", "(I[JI)V", (void *) android_glGetInteger64v__I_3JI },
+{"glGetInteger64v", "(ILjava/nio/LongBuffer;)V", (void *) android_glGetInteger64v__ILjava_nio_LongBuffer_2 },
+{"glGetSynciv", "(JII[II[II)V", (void *) android_glGetSynciv__JII_3II_3II },
+{"glGetSynciv", "(JIILjava/nio/IntBuffer;Ljava/nio/IntBuffer;)V", (void *) android_glGetSynciv__JIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2 },
+{"glGetInteger64i_v", "(II[JI)V", (void *) android_glGetInteger64i_v__II_3JI },
+{"glGetInteger64i_v", "(IILjava/nio/LongBuffer;)V", (void *) android_glGetInteger64i_v__IILjava_nio_LongBuffer_2 },
+{"glGetBufferParameteri64v", "(II[JI)V", (void *) android_glGetBufferParameteri64v__II_3JI },
+{"glGetBufferParameteri64v", "(IILjava/nio/LongBuffer;)V", (void *) android_glGetBufferParameteri64v__IILjava_nio_LongBuffer_2 },
+{"glGenSamplers", "(I[II)V", (void *) android_glGenSamplers__I_3II },
+{"glGenSamplers", "(ILjava/nio/IntBuffer;)V", (void *) android_glGenSamplers__ILjava_nio_IntBuffer_2 },
+{"glDeleteSamplers", "(I[II)V", (void *) android_glDeleteSamplers__I_3II },
+{"glDeleteSamplers", "(ILjava/nio/IntBuffer;)V", (void *) android_glDeleteSamplers__ILjava_nio_IntBuffer_2 },
+{"glIsSampler", "(I)Z", (void *) android_glIsSampler__I },
+{"glBindSampler", "(II)V", (void *) android_glBindSampler__II },
+{"glSamplerParameteri", "(III)V", (void *) android_glSamplerParameteri__III },
+{"glSamplerParameteriv", "(II[II)V", (void *) android_glSamplerParameteriv__II_3II },
+{"glSamplerParameteriv", "(IILjava/nio/IntBuffer;)V", (void *) android_glSamplerParameteriv__IILjava_nio_IntBuffer_2 },
+{"glSamplerParameterf", "(IIF)V", (void *) android_glSamplerParameterf__IIF },
+{"glSamplerParameterfv", "(II[FI)V", (void *) android_glSamplerParameterfv__II_3FI },
+{"glSamplerParameterfv", "(IILjava/nio/FloatBuffer;)V", (void *) android_glSamplerParameterfv__IILjava_nio_FloatBuffer_2 },
+{"glGetSamplerParameteriv", "(II[II)V", (void *) android_glGetSamplerParameteriv__II_3II },
+{"glGetSamplerParameteriv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetSamplerParameteriv__IILjava_nio_IntBuffer_2 },
+{"glGetSamplerParameterfv", "(II[FI)V", (void *) android_glGetSamplerParameterfv__II_3FI },
+{"glGetSamplerParameterfv", "(IILjava/nio/FloatBuffer;)V", (void *) android_glGetSamplerParameterfv__IILjava_nio_FloatBuffer_2 },
+{"glVertexAttribDivisor", "(II)V", (void *) android_glVertexAttribDivisor__II },
+{"glBindTransformFeedback", "(II)V", (void *) android_glBindTransformFeedback__II },
+{"glDeleteTransformFeedbacks", "(I[II)V", (void *) android_glDeleteTransformFeedbacks__I_3II },
+{"glDeleteTransformFeedbacks", "(ILjava/nio/IntBuffer;)V", (void *) android_glDeleteTransformFeedbacks__ILjava_nio_IntBuffer_2 },
+{"glGenTransformFeedbacks", "(I[II)V", (void *) android_glGenTransformFeedbacks__I_3II },
+{"glGenTransformFeedbacks", "(ILjava/nio/IntBuffer;)V", (void *) android_glGenTransformFeedbacks__ILjava_nio_IntBuffer_2 },
+{"glIsTransformFeedback", "(I)Z", (void *) android_glIsTransformFeedback__I },
+{"glPauseTransformFeedback", "()V", (void *) android_glPauseTransformFeedback__ },
+{"glResumeTransformFeedback", "()V", (void *) android_glResumeTransformFeedback__ },
+{"glGetProgramBinary", "(II[II[IILjava/nio/Buffer;)V", (void *) android_glGetProgramBinary__II_3II_3IILjava_nio_Buffer_2 },
+{"glGetProgramBinary", "(IILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/Buffer;)V", (void *) android_glGetProgramBinary__IILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_Buffer_2 },
+{"glProgramBinary", "(IILjava/nio/Buffer;I)V", (void *) android_glProgramBinary__IILjava_nio_Buffer_2I },
+{"glProgramParameteri", "(III)V", (void *) android_glProgramParameteri__III },
+{"glInvalidateFramebuffer", "(II[II)V", (void *) android_glInvalidateFramebuffer__II_3II },
+{"glInvalidateFramebuffer", "(IILjava/nio/IntBuffer;)V", (void *) android_glInvalidateFramebuffer__IILjava_nio_IntBuffer_2 },
+{"glInvalidateSubFramebuffer", "(II[IIIIII)V", (void *) android_glInvalidateSubFramebuffer__II_3IIIIII },
+{"glInvalidateSubFramebuffer", "(IILjava/nio/IntBuffer;IIII)V", (void *) android_glInvalidateSubFramebuffer__IILjava_nio_IntBuffer_2IIII },
+{"glTexStorage2D", "(IIIII)V", (void *) android_glTexStorage2D__IIIII },
+{"glTexStorage3D", "(IIIIII)V", (void *) android_glTexStorage3D__IIIIII },
+{"glGetInternalformativ", "(IIII[II)V", (void *) android_glGetInternalformativ__IIII_3II },
+{"glGetInternalformativ", "(IIIILjava/nio/IntBuffer;)V", (void *) android_glGetInternalformativ__IIIILjava_nio_IntBuffer_2 },
+};
+
+int register_android_opengl_jni_GLES30(JNIEnv *_env)
+{
+    int err;
+    err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods));
+    return err;
+}
diff --git a/core/jni/android_os_Trace.cpp b/core/jni/android_os_Trace.cpp
index 1315291..01d02c5 100644
--- a/core/jni/android_os_Trace.cpp
+++ b/core/jni/android_os_Trace.cpp
@@ -86,6 +86,11 @@
     atrace_set_debuggable(allowed);
 }
 
+static void android_os_Trace_nativeSetTracingEnabled(JNIEnv* env,
+        jclass clazz, jboolean enabled) {
+    atrace_set_tracing_enabled(enabled);
+}
+
 static JNINativeMethod gTraceMethods[] = {
     /* name, signature, funcPtr */
     { "nativeGetEnabledTags",
@@ -109,6 +114,9 @@
     { "nativeSetAppTracingAllowed",
             "(Z)V",
             (void*)android_os_Trace_nativeSetAppTracingAllowed },
+    { "nativeSetTracingEnabled",
+            "(Z)V",
+            (void*)android_os_Trace_nativeSetTracingEnabled },
 };
 
 int register_android_os_Trace(JNIEnv* env) {
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 0014877..ad7c51a 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -909,7 +909,7 @@
         <!-- Declare that this application requires access to restricted accounts of a certain
              type. The default value is null and restricted accounts won\'t be visible to this
              application. The type should correspond to the account authenticator type, such as
-             "com.google". Only usable by system apps. -->
+             "com.google". -->
         <attr name="restrictedAccountType" format="string"/>
         <!-- Declare that this application requires an account of a certain
              type. The default value is null and indicates that the application can work without
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 3dc5137..d081603 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2411,9 +2411,14 @@
     <string name="js_dialog_title">The page at \"<xliff:g id="title">%s</xliff:g>\" says:</string>
     <!-- Default title for a javascript dialog -->
     <string name="js_dialog_title_default">JavaScript</string>
-    <!-- Message in a javascript dialog asking if the user wishes to leave the
-             current page -->
-    <string name="js_dialog_before_unload">Navigate away from this page?\n\n<xliff:g id="message">%s</xliff:g>\n\nTouch OK to continue, or Cancel to stay on the current page.</string>
+    <!-- Title for the unload javascript dialog -->
+    <string name="js_dialog_before_unload_title">Confirm Navigation</string>
+    <!-- Text for the positive button on the unload javascript dialog -->
+    <string name="js_dialog_before_unload_positive_button">Leave this Page</string>
+    <!-- Text for the negative button on the unload javascript dialog -->
+    <string name="js_dialog_before_unload_negative_button">Stay on this Page</string>
+    <!-- Message in a javascript dialog asking if the user wishes to leave the current page -->
+    <string name="js_dialog_before_unload"><xliff:g id="message">%s</xliff:g>\n\nAre you sure you want to navigate away from this page?</string>
 
     <!-- Title of the WebView save password dialog.  If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. -->
     <string name="save_password_label">Confirm</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 0d3500c..ae02d73 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -545,6 +545,9 @@
   <java-symbol type="string" name="ime_action_search" />
   <java-symbol type="string" name="ime_action_send" />
   <java-symbol type="string" name="invalidPin" />
+  <java-symbol type="string" name="js_dialog_before_unload_positive_button" />
+  <java-symbol type="string" name="js_dialog_before_unload_negative_button" />
+  <java-symbol type="string" name="js_dialog_before_unload_title" />
   <java-symbol type="string" name="js_dialog_before_unload" />
   <java-symbol type="string" name="js_dialog_title" />
   <java-symbol type="string" name="js_dialog_title_default" />
diff --git a/docs/html/distribute/distribute_toc.cs b/docs/html/distribute/distribute_toc.cs
index ad3121c..3ea11bf 100644
--- a/docs/html/distribute/distribute_toc.cs
+++ b/docs/html/distribute/distribute_toc.cs
@@ -1,106 +1,71 @@
 <ul id="nav">
 
   <li class="nav-section">
-    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/index.html">
-      <span class="en">Google Play</span></a>
-    </div>
+    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/index.html">Google Play</a></div>
     <ul>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/about/visibility.html">
-           <span class="en">Visibility</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/about/monetizing.html">
-           <span class="en">Monetizing</a></li>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/about/distribution.html">
-           <span class="en">Distribution</a></li>
+      <li><a href="<?cs var:toroot ?>distribute/googleplay/about/visibility.html">Visibility</a></li>
+      <li><a href="<?cs var:toroot ?>distribute/googleplay/about/monetizing.html">Monetizing</a></li>
+      <li><a href="<?cs var:toroot ?>distribute/googleplay/about/distribution.html">Distribution</a></li>
     </ul>  
   </li>
 
   <li class="nav-section">
-    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/publish/index.html">
-      <span class="en">Publishing</span></a>
-    </div>
+    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/publish/index.html">Publishing</a></div>
     <ul>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/publish/register.html">
-           <span class="en">Get Started</span>
-          </a></li>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/publish/console.html">
-           <span class="en">Developer Console</span>
-          </a></li>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/publish/preparing.html">
-           <span class="en">Publishing Checklist</span>
-          </a></li>
-
-     </ul>
+      <li><a href="<?cs var:toroot ?>distribute/googleplay/publish/register.html">Get Started</a></li>
+      <li><a href="<?cs var:toroot ?>distribute/googleplay/publish/console.html">Developer Console</a></li>
+      <li><a href="<?cs var:toroot ?>distribute/googleplay/publish/preparing.html">Publishing Checklist</a></li>
+    </ul>
   </li>
   
 <!--  <li class="nav-section">
-    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/developer-console.html">
-        <span class="en">The Developer Console</span>
-      </a>
+    <div class="nav-section-header">
+      <a href="<?cs var:toroot ?>distribute/googleplay/developer-console.html">The Developer Console</a>
     </div>
     <ul>
-      <li class="nav-section"><a href="<?cs var:toroot ?>distribute/googleplay/register.html">
-        <span class="en">Get Started</span></a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/distribution-controls.html">
-        <span class="en">Managing Distribution</span>
-        </a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/pricing-billing.html">
-        <span class="en">Pricing and Billing</span>
-        </a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/app-data.html">
-        <span class="en">Reviewing App Data</span>
-        </a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/advanced-options.html">
-        <span class="en">Advanced Options</span>
-        </a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/publishing.html">
-        <span class="en">Publishing and Updating</span>
-        </a></li>
+      <li class="nav-section"><a href="<?cs var:toroot ?>distribute/googleplay/register.html">Get Started</a></li>
+      <li><a href="<?cs var:toroot ?>distribute/googleplay/distribution-controls.html">Managing Distribution</a></li>
+      <li><a href="<?cs var:toroot ?>distribute/googleplay/pricing-billing.html">Pricing and Billing</a></li>
+      <li><a href="<?cs var:toroot ?>distribute/googleplay/app-data.html">Reviewing App Data</a></li>
+      <li><a href="<?cs var:toroot ?>distribute/googleplay/advanced-options.html">Advanced Options</a></li>
+      <li><a href="<?cs var:toroot ?>distribute/googleplay/publishing.html">Publishing and Updating</a></li>
     </ul>
   </li> end of Developer Console -->
-  
+
    <li class="nav-section">
-     <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/promote/index.html">
-       <span class="en">Promoting</span></a>
+     <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/promote/index.html">Promoting</a>
      </div>
      <ul>
-<!--   <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/product-pages.html">
-        <span class="en">Your Product Pages</a></li> 
--->
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/linking.html">
-        <span class="en">Linking to Your Products</a></li>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/badges.html">
-        <span class="en">Google Play Badges</a></li>
-       <li><a href="<?cs var:toroot ?>distribute/promote/device-art.html">
-        <span class="en">Device Art Generator</a></li>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/brand.html">
-        <span class="en">Brand Guidelines</a></li>
+<!--   <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/product-pages.html">Your Product Pages</a></li> -->
+       <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/linking.html">Linking to Your Products</a></li>
+       <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/badges.html">Google Play Badges</a></li>
+       <li><a href="<?cs var:toroot ?>distribute/promote/device-art.html">Device Art Generator</a></li>
+       <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/brand.html">Brand Guidelines</a></li>
      </ul>
    </li>
 
-
   <li class="nav-section">
-    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/quality/index.html">
-      <span class="en">App Quality</span></a>
-    </div>
+    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/quality/index.html">App Quality</a></div>
     <ul>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/quality/core.html">
-          <span class="en">Core App Quality</span>
-         </a></li>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/quality/tablet.html">
-          <span class="en">Tablet App Quality</span>
-         </a></li>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/strategies/app-quality.html">
-          <span class="en">Improving App Quality</span>
-         </a></li>
-
+       <li><a href="<?cs var:toroot ?>distribute/googleplay/quality/core.html">Core App Quality</a></li>
+       <li><a href="<?cs var:toroot ?>distribute/googleplay/quality/tablet.html">Tablet App Quality</a></li>
+       <li><a href="<?cs var:toroot ?>distribute/googleplay/strategies/app-quality.html">Improving App Quality</a></li>
     </ul>
   </li> 
 
+   <li class="nav-section">
+     <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/policies/index.html">Policies</a></div>
+     <ul>
+       <li><a href="<?cs var:toroot ?>distribute/googleplay/policies/spam.html">Spam</a></li>
+       <li><a href="<?cs var:toroot ?>distribute/googleplay/policies/ip.html">Intellectual<br />Property</a></li> 
+       <li><a href="<?cs var:toroot ?>distribute/googleplay/policies/ads.html">Ads</a></li>
+     </ul>
+   </li>
 
 <!--    
    <li class="nav-section">
     <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/after.html">
-      <span class="en">After Launch</span></a>
+      After Launch</a>
     </div>
     <ul>
        <li><a href="<?cs var:toroot ?>distribute/googleplay/errors.html.html">Reviewing Errors</a></li>
@@ -111,22 +76,14 @@
 -->
 
   <li class="nav-section">
-    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/index.html">
-      <span class="en">Spotlight</span></a>
-    </div>
+    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/index.html">Spotlight</a></div>
     <ul>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/tablets.html">
-          <span class="en">Tablet Stories</span>
-         </a></li>
+       <li><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/tablets.html">Tablet Stories</a></li>
     </ul>
   </li> 
 
   <li class="nav-section">
-    <div class="nav-section-header empty">
-      <a href="<?cs var:toroot ?>distribute/open.html">
-        <span class="en">Open Distribution</span>
-      </a>
-    </div>
+    <div class="nav-section-header empty"><a href="<?cs var:toroot ?>distribute/open.html">Open Distribution</a></div>
   </li>
 </ul>
   
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/policies/ads.jd b/docs/html/distribute/googleplay/policies/ads.jd
new file mode 100644
index 0000000..8920499
--- /dev/null
+++ b/docs/html/distribute/googleplay/policies/ads.jd
@@ -0,0 +1,352 @@
+page.title=Ads
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+  <h2>In This Document</h2>
+  <ol>
+    <li><a href="#content-maturity">Content and Maturity</a></li>
+    <li><a href="#context">Context and Behavior</a></li>
+    <li><a href="#disclosure" style="clear:right">Disclosure</a></li>
+    <li><a href="#impersonation">Impersonation of System UI</a></li>
+    <li><a href="#adwalls">Adwalls</a></li>
+    <li><a href="#interfering" style="clear:right;">Interference with Ads and Websites</a></li>
+  </ol>
+
+  <h2>More Resources</h2>
+  <ol>
+    <li><a href="http://play.google.com/about/developer-content-policy.html" target="_policies">Developer Program Policies</a></li>
+    <li><a href="http://www.android.com/us/developer-distribution-agreement.html#showlanguages" target="_policies">Developer Distribution Agreement</a></li>
+    <li><a href="http://support.google.com/googleplay/android-developer/answer/188189" target="_policies">Maturity Ratings</a></p>
+  </ol>
+</div>
+</div>
+
+<p>
+  Google Play policies guide how you can use ads in your apps, to help ensure
+  the best experience for users visiting and downloading apps from the store.
+</p>
+
+<p>
+  In general, for the purposes of policy, the content of ads displayed by your
+  app is considered part of your app. As an app developer, it is your
+  responsibility to ensure that the content, context, and behavior of ads in
+  your apps conforms to Google Play policies.
+</p>
+
+<p>
+  Before you publish, make sure you understand Google Play ad policies and how
+  to display ads in conformance with those policies. The sections below
+  highlight best practices and common examples to help you avoid the most
+  common types of policy violations.
+</p>
+
+<p>
+  For more information about Google Play policies that apply to your apps and
+  content, please see the <a href=
+  "http://play.google.com/about/developer-content-policy.html" target=
+  "_policies">Developer Program Policies</a> and <a href=
+  "http://play.google.com/about/developer-distribution-agreement.html" target=
+  "_policies">Developer Distribution Agreement</a>.
+</p>
+
+
+<h2 id="content-maturity">Content and Maturity</h2>
+
+<div class="example-block bad">
+  <div class="heading">Ad maturity exceeds app</div>
+  <img src="{@docRoot}images/gp-policy-ads-maturity-violation.png">
+</div>
+
+<p>
+  From a policy perspective, ads shown in your app are part of your content
+  and your app is responsible for any violations. If an ad shown in your app
+  violates Google Play policies, your app may be suspended or your developer
+  account terminated.
+</p>
+
+<p>
+  For this reason, it's important for you to be be aware of what ads will be
+  displayed in your app and to manage the ads content according to Google Play
+  policies. Here are some guidelines:
+</p>
+
+<ul>
+    <li>
+        <strong>Ads must not violate Content Policy</strong>&mdash;Ads in
+        your app must not violate the terms of Google Play’s Content Policy,
+        including those concerning illegal activities, violence, sexually
+        explicit content, or privacy violations.
+    </li>
+    <li>
+        <strong>Ads maturity must be consistent with your app's
+        maturity</strong>&mdash;Content shown in your ads must be consistent
+        with the app’s maturity rating in Google Play. Especially, ads content
+        should never exceed your app's maturity rating, even if the ads content
+        by itself complies with general policies.
+    </li>
+</ul>
+
+<p>
+  In the example at right, the app's maturity rating is set to
+  "Everyone", which is the lowest maturity level on Google Play. By choosing
+  the "Everyone" maturity level, the developer is declaring that all of the
+  content in the app, <em>including ads</em>, is suitable for all users
+  regardless of age.
+</p>
+
+<p>
+  The example app violates Google Play policies by displaying ad content with a
+  higher maturity level&mdash;ad content showing gambling, profanity, user
+  location, suggestive content, or content from another app with higher
+  maturity exceeds the "Everyone" maturity rating. Because the ad's
+  maturity is higher than the app's maturity level, the app itself is in
+  violation of policy. To correct the problem, the developer must either
+  restrict ads content to "Everyone" level or raise the app's maturity rating.
+</p>
+
+<p>
+  For detailed information about how to choose the appropriate maturity level
+  for your app, or to assess the maturity requirement of ads in your app, see
+  <a href=
+  "http://support.google.com/googleplay/android-developer/answer/188189"
+  target="_policies">Rating your application content for Google Play</a>.
+</p>
+
+
+<h2 id="context">Context and Behavior</h2>
+
+<p>
+  If your app displays ads, it should do so in ways that do not interrupt users,
+  mislead them into clicking on ads, or make changes outside the app without
+  the user's knowledge or consent. Here are some guidelines:
+</p>
+
+<ul>
+  <li>
+    <strong>Display your ads within your UI</strong>&mdash;If possible,
+    display ads only within your app's UI. This leads to a better user
+    experience and helps avoid policy violations
+  </li>
+
+  <li>
+    <strong>Make sure app origin is clear</strong>&mdash;When you display an
+    ad, it must be clear to the user that the ad has originated from your app.
+    If you show the ad in your app's UI while your app has focus, the user
+    understands the ad origin without explicit attribution. However, if you
+    display the ad outside of your app, such as in a notification, you must
+    explicitly indicate the origin.
+  </li>
+
+  <li>
+    <strong>Don't make changes outside of the app without consent</strong>
+   &mdash;Ads must not make changes outside of the app without the user's
+    full knowledge and consent. For example, ads should not install shortcuts,
+    bookmarks, or icons, or change default settings without user consent.
+  </li>
+
+  <li>
+    <strong>Changes outside the app must be reversible</strong>&mdash;If an
+    ad makes changes outside the app as described above, the changes (and
+    origin app) must be evident and easily reversible. For example, the user
+    must be able to locate and reverse the changes by adjusting settings,
+    changing ad preferences in the app, or uninstalling the app altogether.
+  </li>
+
+  <li>
+    <strong>Notification ads require user opt-in</strong>&mdash;Your app
+    should not create <a href=
+    "{@docRoot}design/patterns/notifications.html">notifications</a>
+    containing ads unless the user has specifically opted-in to this behavior
+    and is able to easily opt-out.
+  </li>
+
+  <li>
+    <strong>Use low priority for notification ads</strong>&mdash;Always
+    assign your notification ads <a href="
+    {@docRoot}reference/android/app/Notification.html#PRIORITY_LOW">low
+    priority</a> (for API level 16 and above).
+  </li>
+</ul>
+
+<div class="example-block bad" style="width:400px;margin:.5em 0 0 2em;">
+    <div class="heading">Does not fully indicate origin app</div>
+    <img src="{@docRoot}images/gp-policy-ads-notif-attr-violation.png">
+</div>
+<div class="example-block good" style="width:400px;margin:.5em 0 0 2em;">
+    <div class="heading">Indicates origin app by name and icon</div>
+    <img src="{@docRoot}images/gp-policy-ads-notif-attr.png">
+</div>
+
+<p>
+  In particular, note that notification ads must clearly identify your app as
+  the ad origin. If your app sends notification ads that do not sufficiently
+  identify your app as the origin, the app will be in violation of policy.
+</p>
+
+<p>
+  To identify your app as the origin, you should display the <strong>app's full
+  name and and icon</strong> in the notification to provide the clearest
+  identification and best policy compliance. Displaying a partial app name can
+  also be sufficient, provided the name unambiguously identifies your app.
+</p>
+
+<p>
+  Above right is an example notification ad that violates ad policy by not
+  providing attribution of the origin app. Below right, the notification ads
+  comply with policy by providing both the app icon and full app name (in this
+  case, "Turtle Test").
+</p>
+
+
+<h2 id="disclosure" style="clear:right">Disclosure of Ads to Users</h2>
+
+<p>
+  It's important to sufficiently disclose to users how your app will use ads.
+  You must make it easy for users to understand what ads will be shown in your
+  app, where they will be shown, and what the associated behaviors are, if any.
+  Further, you should ask for user consent and provide options for managing ads
+  or opt-out. Here are some guidelines:
+</p>
+
+<ul>
+  <li>
+    <strong>Tell users about your ads</strong>&mdash;Create a simple,
+    complete disclosure that tells users how your app uses ads, where the ads
+    are shown, and how they can manage ad options. Take common-sense steps to
+    make the disclosure as clear as possible.
+  </li>
+
+  <li>
+    <strong>Make sure users know</strong>&mdash;Present your ads disclosure
+    is an easy-to-see location, rather than hiding it where users are not
+    likely to find it.
+  </li>
+
+  <li>
+    <strong>Ask for consent (opt-in) at launch</strong>&mdash;Where possible,
+    include your ads disclosure in the app description as well as in an Ads
+    Terms, End User License Agreement (EULA), or similar document. Display the
+    terms at first launch and ask for the user's consent before continuing to
+    the app.
+  </li>
+</ul>
+
+<p>
+  A recommended approach is to provide an ads disclosure in an End-User License
+  Agreement (EULA). The disclosure should be clear and succinct and displayed
+  in a modal dialog that asks the user to agree to the terms before using the
+  app.
+</p>
+
+<p>
+  If your app adds homescreen icons and/or browser bookmarks, an acceptable
+  practice for revealing that behavior is to provide a disclosure in both the
+  app description and an opt-in EULA on app launch. This ensures that the
+  behaviors are clearly explained to the user up-front and requires the user’s
+  consent in a pop-up EULA to continue using the app.
+</p>
+
+<div class="example-block good" style="width:213px;margin-right:2em;">
+  <div class="heading">Disclosure in Terms</div>
+  <img src="{@docRoot}images/gp-policy-ads-terms.png">
+</div>
+
+<div class="example-block good" style="width:213px;">
+  <div class="heading">Disclosure in EULA</div>
+  <img src="{@docRoot}images/gp-policy-ads-eula.png">
+</div>
+
+<div class="example-block bad" style="width:213px;margin-left:0em;">
+  <div class="heading">Disclosure is hidden</div>
+  <img src="{@docRoot}images/gp-policy-ads-eula-violation.png">
+</div>
+
+<p style="clear:right">
+  Above left is an example of ads disclosure that is hidden in a long EULA. The
+  disclosure information itself is not clearly indicated in the document text
+  and it's not visible unless the user happens to scroll down far enough in the
+  EULA. Above middle and right show two alternative approaches that
+  present the disclosure in an obvious and clear manner at the top of a
+  EULA and in a dedicated Terms agreement. 
+</p>
+
+
+<h2 id="impersonation">Impersonation of System UI</h2>
+
+<div class="example-block bad">
+  <div class="heading">Ad impersonates system dialog</div>
+  <img src="{@docRoot}images/gp-policy-ads-impersonate-violation.png">
+</div>
+
+<p>
+  Your app must not display any ad that attempts to impersonate or represent a
+  system function or UI component. If such an ad is displayed in your app, your
+  app will be in violation of policy and subject to suspension. Here are some
+  guidelines:
+</p>
+
+<ul>
+  <li>
+    <strong>No fake system dialogs or warnings</strong>&mdash;Any ad that
+    presents itself as a system dialog or warning and asks for user input is in
+    violation of Google Play policies.
+  </li>
+
+  <li>
+    <strong>No fake app updates</strong>&mdash;Ads should not impersonate
+    system UI for app updates.
+  </li>
+</ul>
+
+<p>
+  At right is an example of a pop-up ad impersonating a system dialog, warning
+  the user about viruses. This is a violation of policy.
+</p>
+
+
+<h2 id="adwalls">Adwalls</h2>
+
+<div class="example-block good" style="width:213px;">
+  <div class="heading">Adwall lets user cancel</div>
+  <img src="{@docRoot}images/gp-policy-ads-paywall.png">
+</div>
+
+<div class="example-block bad" style="width:213px;">
+  <div class="heading">Adwall forces user action</div>
+  <img src="{@docRoot}images/gp-policy-ads-paywall-violation.png">
+</div>
+
+<p>
+  If your app uses adwalls to drive affiliate traffic, those adwalls must not
+  force the user to click on ads or submit personal information for advertising
+  purposes before using the app.
+</p>
+
+<p>
+  Forcing a user action in an adwall is not only a poor user experience, it is
+  a violation of Google Play policies.
+</p>
+
+<p>
+  For this reason, <strong>all adwalls must give the user the option to
+  cancel</strong> or otherwise dismiss the ad without penalty.
+</p>
+
+<p>
+  At right is an example of an app that requires the user to click through the
+  ad to fully use the app. This is a violation of policy.
+</p>
+
+<p>
+  The adjacent example demonstrates an adequate option to let the user dismiss
+  the ad wall easily by cancelling.
+</p>
+
+
+<h2 id="interfering" style="clear:right;">Interference with Third-party Ads and Websites</h2>
+
+<p>
+  Ads associated with your app <strong>must not interfere</strong> with any
+  other ads originating in other applications.
+</p>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/policies/index.jd b/docs/html/distribute/googleplay/policies/index.jd
new file mode 100644
index 0000000..fb46055
--- /dev/null
+++ b/docs/html/distribute/googleplay/policies/index.jd
@@ -0,0 +1,59 @@
+page.title=Google Play Policies and Guidelines
+page.metaDescription=Guidelines and tips for creating apps that comply with Google Play content and distribution policies.
+@jd:body
+
+<p>
+  Before publishing your apps on Google Play, take a few minutes to read and
+  understand the content and distribution policies that apply to all apps
+  in the store. These policies help to keep Android and Google Play an enjoyable
+  and trusted platform for content consumers and developers alike.
+</p>
+
+<p>
+  The documents below highlight important policy areas and provide tips to help
+  you create policy-compliant apps. You'll also find examples and guidance on common
+  policy questions that can help your app stay clear of practices that can result in
+  low ratings or even suspensions from the store.
+</p>
+
+<p>
+  For complete information about Google Play policies, please see the full
+  <a href="http://play.google.com/about/developer-content-policy.html" target=
+  "_policies">Developer Program Policies</a> and <a href=
+  "http://play.google.com/about/developer-distribution-agreement.html" target=
+  "_policies">Developer Distribution Agreement</a> documents.
+</p>
+
+<div class="vspace size-1">
+  &nbsp;
+</div>
+<div class="layout-content-row">
+  <div class="layout-content-col span-4">
+    <h4>
+      Spam
+    </h4>
+    <p>
+      Make sure that your app does not present content that is unwanted,
+      deceptive, repetitive, or unrelated to the core function of the app.
+    </p><a href="{@docRoot}distribute/googleplay/policies/spam.html">Learn more &raquo;</a>
+  </div>
+  <div class="layout-content-col span-4">
+    <h4>
+      Intellectual Property
+    </h4>
+    <p>
+      Tips and examples of how to use intelletual property (IP) properly,
+      including when to ask permission to use someone else's copyright or
+      trademark.
+    </p><a href="{@docRoot}distribute/googleplay/policies/ip.html">Learn more &raquo;</a>
+  </div>
+  <div class="layout-content-col span-4">
+    <h4>
+      Ads
+    </h4>
+    <p>
+      Make sure that the ads displayed in your app follow the Google Play Content
+      Policy and meet the maturity rating that you have selected for your app.
+    </p><a href="{@docRoot}distribute/googleplay/policies/ads.html">Learn more &raquo;</a>
+  </div>
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/policies/ip.jd b/docs/html/distribute/googleplay/policies/ip.jd
new file mode 100644
index 0000000..0d1f68d
--- /dev/null
+++ b/docs/html/distribute/googleplay/policies/ip.jd
@@ -0,0 +1,345 @@
+page.title=Intellectual Property
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+  <h2>In This Document</h2>
+  <ol>
+    <li><a href="#copyright">Copyright Infringement</a></li>
+    <li><a href="#impersonation">Impersonation</a></li>
+    <li><a href="#trademarks">Trademark Infringement</a></li>
+    <li><a href="#other">DDA 4.4 Prohibited Actions</a></li>
+  </ol>
+
+  <h2>More Resources</h2>
+  <ol>
+    <li><a href="http://play.google.com/about/developer-content-policy.html"
+    target="_policies">Developer Program Policies</a></li>
+    <li><a href="http://www.android.com/us/developer-distribution-agreement.html#showlanguages"
+    target="_policies">Developer Distribution Agreement</a></li>
+  </ol>
+</div>
+</div>
+
+<p>
+  Google Play policies protect your intellectual property (IP) as well as that
+  of other app developers and content creators in the store. The policies and
+  their enforcements help ensure proper use of copyright, trademarks, and
+  developer identity in Google Play.
+</p>
+
+<p>
+  As an app developer, these IP policies benefit you. At the same time, it's
+  your responsibility to ensure that your app does not violate the IP of other
+  developers or content creators. Violations of IP-related policy may result in
+  suspension of your apps from the store and termination of your developer
+  account.
+</p>
+
+<p>
+  This document introduces several key areas of IP-related policy that you
+  should understand before publishing on Google Play. In each area you'll find
+  best practices and examples to help you avoid common types of mistakes and
+  violations.
+</p>
+
+<p>
+  For more information about Google Play policies that apply to your apps and
+  content, please see the <a href=
+  "http://play.google.com/about/developer-content-policy.html" target=
+  "_policies">Developer Program Policies</a> and <a href=
+  "http://play.google.com/about/developer-distribution-agreement.html" target=
+  "_policies">Developer Distribution Agreement</a>.
+</p>
+
+
+
+<h2 id="copyright">Copyright Infringement</h2>
+
+<p>
+  Copyright is the legal right granted to an author or creator for a literary,
+  dramatic or artistic piece of work. As soon as you create an original piece
+  of work and fix it in a tangible medium, the work is automatically protected
+  by copyright law and you are the owner of the copyright. Likewise, when other
+  people create content, they may own the copyrights for those works.
+</p>
+
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+<h2>How to report infringements</h2>
+<p>If you feel your copyright is being infringed, you may file a Digital Millenium
+   Copyright Act (DMCA) request. Please see <a 
+   href="http://support.google.com/bin/request.py?&product=androidmarket&contact_type=lr_dmca"
+   target="_policies">copyright procedures</a> for more information.</p>
+</div>
+</div>
+
+<p>
+  Copyright infringement is an improper or unauthorized use of a copyrighted
+  work. If you publish an app in Google Play that uses another party's copyrighted
+  works improperly or without permission, your apps can be suspended and your
+  developer account terminated.
+</p>
+
+<p>
+  As you design your app and prepare for publishing, make sure to review Google
+  Play policies and analyze all of your content. If your app uses or links to
+  another party's original work, make sure that your app is not infringing on
+  copyright. Not all uses of another party’s work are infringements on
+  copyright, and the rules vary by country and can be complex.
+</p>
+
+<p>
+  If you are unsure whether your use of another party's work infringes on a
+  copyright, consider getting legal advice before publishing, or simply request
+  permission to use the work from the copyright owner.
+</p>
+
+<p>
+  Here are some guidelines to help you avoid copyright infringement policy
+  violations:
+</p>
+
+<ul>
+  <li>
+    <strong>Respect copyright laws</strong>&mdash;Do not let your app infringe
+    on the copyrights of others. That includes linking to other apps or web
+    sites that contain obviously infringing material (please refer to the <a href="
+    {@docRoot}distribute/googleplay/policies/spam.html#webview-spam">Spam in WebViews</a> guidelines), and using icons or images that are obvious infringements.
+  </li>
+
+  <li>
+    <strong>Know your app's content</strong>&mdash;Before you publish, look
+    for content that may be protected by trademark or copyright in your app
+    and get legal advice if necessary. Protected work could typically include
+    product names, brands, images, music, and similar works.
+  </li>
+
+  <li>
+    <strong>Create original work</strong>&mdash;If you’re not sure whether
+    something will violate another party's copyright, the safest approach is to
+    create something that's completely original, such as images or audio
+    that you’ve created yourself. When you create your own original content,
+    you rarely have to worry about infringing on existing copyright.
+  </li>
+
+  <li>
+    <strong>Ask permission to use copyrighted work</strong>&mdash;If you want
+    to use another party's copyrighted work in your app, you should ask for
+    permission from the work's creator or copyright owner and include
+    appropriate copyright attribution.
+  </li>
+</ul>
+
+<p>
+  A common misunderstanding is believing that your app may use copyrighted
+  content without permission, provided that you clearly indicate that your app
+  is not the "official" app that readers may be familiar with. That is not the
+  case. Even if you let users know that your app is "unofficial", it still
+  violates Google Play policies if it uses or links to copyrighted content
+  without permission. Also, this type of "unofficial" app may violate <a
+  href="#impersonation">impersonation policies</a>.
+</p>
+
+<p>
+  The example app below shows an app that uses screenshots/images of known
+  artists without their authorization and lists popular songs. The combination
+  of these may induce users to download music ringtones that infringe on
+  copyright. This is a violation of Google Play policy.
+</p>
+
+<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
+  <div class="heading">Images and downloads that violate copyright</div>
+  <img src="{@docRoot}images/gp-policy-ip-copyright-violation.png">
+</div>
+
+
+<h2 id="impersonation">Impersonation</h2>
+
+<p>
+  Impersonation is when an app attempts to imply a relationship to another app
+  or developer, where no relationship actually exists.
+</p>
+
+<p>
+  For example, if your app displays the brand, icon, or title from another app
+  in order to get to users to download your app, you are leading users to
+  believe that your app is developed by the same entity as the other app and
+  offers similar content or experience. This is an impersonation of the other
+  app and developer, and it is a violation of Google Play policy. If you
+  publish apps that violate impersonation policies, your apps can be suspended
+  and your developer account terminated.
+</p>
+
+<p>
+  No matter what type of app you offer or what your motivation, don’t try to
+  imply an endorsement or relationship to another company or product where none
+  exists. Don’t try to establish your app as the "official" version of another
+  party's work by prominently featuring their brand names or trademarks in your
+  app title or description.
+</p>
+
+<p>
+  Even if your app description states that your app is an "unofficial" version,
+  the use of the other app's branding, trademarks, and other content still can
+  violate policy by presenting content that isn’t yours.
+</p>
+
+<p>
+  Here are some guidelines:
+</p>
+
+<ul>
+  <li>
+    <strong>Don't pretend to be someone else</strong>&mdash; Don't represent
+    that your content is produced by another company or organization if that is
+    not the case.
+  </li>
+
+  <li>
+    <strong>Don't support infringing sites or apps</strong>&mdash; Don't divert
+    users or provide links to any other site that mimics Google Play or
+    represents itself as another application or service.
+  </li>
+
+  <li>
+    <strong>Don't use another app's branding</strong>&mdash; Don’t try to pass
+    off your app as the official version of someone else’s property by using a
+    person or entity (or brand) name in your app title or description.
+  </li>
+</ul>
+
+<p>
+  Below is an example of an "unofficial" app that violates Google Play policy
+  by impersonating another company and an existing product. Specifically:
+</p>
+
+<ul>
+  <li>The example app has a name and icon that appear to be impersonating an
+  existing product.
+  </li>
+
+  <li>The example developer name implies an endorsement or relationship to
+  another company and their products where none exists.
+  </li>
+</ul>
+
+<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
+  <div class="heading">App name, icon, and developer name that impersonate another</div>
+  <img src="{@docRoot}images/gp-policy-ip-impersonation-violation.png">
+</div>
+
+
+<h2 id="trademarks">Trademark Infringement</h2>
+
+<p>
+  A trademark is a brand that uniquely identifies a product and distinguishes
+  it from other products. It can be a word, name, symbol, or combination of
+  those that is intended to identify the source of the product. A trademark is
+  specifically acquired by a company or other entity through a legal process
+  and once acquired gives the owner exclusive rights to the trademark usage.
+</p>
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+<h2>How to report infringements</h2>
+<p>If you feel your trademark is being infringed, you can request a content review.
+See <a href="http://support.google.com/bin/static.py?&ts=1114905&page=ts.cs"
+target="_policies">Removing content from Google</a> for more information.</p>
+</div>
+</div>
+
+<p>
+  Trademark infringement is improper or unauthorized use of a trademark. Google
+  Play policies prohibit apps that infringe trademarks. If you publish apps in
+  Google Play that use another party's trademarks, your apps can be suspended
+  and your developer account terminated.
+</p>
+
+<p>
+  As you design your app and prepare for publishing, make sure to review Google
+  Play policies and analyze all of your content. If your app uses a trademark
+  not owned by you, or if you are not sure whether a brand is a trademark, you
+  should get legal advice before publishing. As with copyright, the rules vary
+  by country and can be complex.
+</p>
+
+<p>
+  Here are some guidelines for avoiding trademark infringement policy
+  violations:
+</p>
+
+<ul>
+  <li>
+    <strong>Understand and follow trademark laws</strong>&mdash;Don't let your
+    app infringe on the trademarks of others.
+  </li>
+
+  <li>
+    <strong>Know your app's content</strong>&mdash;Before you publish, look for
+    brands and potential trademarks used in your app and store listing and get
+    legal advice if necessary.
+  </li>
+
+  <li>
+    <strong>Use a distinct name</strong>&mdash;Don't give your app a name that
+    is confusingly similar to another company's trademark.
+  </li>
+
+  <li>
+    <strong>Don't use trademarks to imply a relationship</strong>&mdash;Don't
+    describe your app using another company's trademarks in a way that implies
+    an endorsement by or affiliation with the other company.
+  </li>
+
+  <li>
+    <strong>Use a distinct app icon and logo</strong>&mdash;Don't use a
+    modified version of another company’s trademarked logo.
+  </li>
+</ul>
+
+<p>
+  A common misunderstanding is believing that your app may use a brand or
+  trademark without permission, provided you clearly indicate that the app is
+  not the "official" or original app. That is not the case. Even if you let
+  users know that your app is "unofficial", it still violates Google Play
+  policies if it uses another party's trademarks. Also, this type of
+  "unofficial" app may violate <a href="#impersonation">impersonation
+  policies</a>.
+</p>
+
+<p>
+  Below is an example app that violates Google Play policies by infringing on
+  another party's trademarks. Specifically:
+</p>
+
+<ul>
+  <li>The example app name is confusingly similar to another party's trademark.</li>
+  <li>The example app icon is a modified version of a another party's logo.</li>
+</ul>
+
+<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
+  <div class="heading">App name and icon that infringe trademarks</div>
+  <img src="{@docRoot}images/gp-policy-ip-trademark-violation.png">
+</div>
+
+
+<h2 id="other">DDA 4.4 Prohibited Actions</h2>
+
+<p>
+  When you publish an app on Google Play, you agree to the terms of the
+  Developer Distribution Agreement (DDA). Section 4.4 of the DDA prohibits certain
+  types of actions on your part. For reference, you agree that you will not
+  engage in any activity with the Market, including the development or
+  distribution of Products, that interferes with, disrupts, damages, or
+  accesses in an unauthorized manner the devices, servers, networks, or other
+  properties or services of any third party including, but not limited to,
+  Android users, Google or any mobile network operator.
+</p>
+
+<p>
+  For details, please refer to the complete <a href=
+  "http://play.google.com/about/developer-distribution-agreement.html" target=
+  "_policies">Developer Distribution Agreement</a>.
+</p>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/policies/spam.jd b/docs/html/distribute/googleplay/policies/spam.jd
new file mode 100644
index 0000000..602c89a
--- /dev/null
+++ b/docs/html/distribute/googleplay/policies/spam.jd
@@ -0,0 +1,421 @@
+page.title=Spam
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+  <h2>In This Document</h2>
+  <ol>
+    <li><a href="#keyword-spam">Spam in App Title and Description</a></li>
+    <li><a href="#ratings">Spam in Ratings and Reviews</a></li>
+    <li><a href="#webview-spam">Spam in WebViews</a></li>
+    <li><a href="#wizard-spam">Spam from Wizards</a></li> 
+    <li><a href="#message-spam">Spam in Messaging</a></li>
+  </ol>
+
+  <h2>More Resources</h2>
+  <ol>
+    <li><a href="http://play.google.com/about/developer-content-policy.html" target="_policies">Developer Program Policies</a></li>
+    <li><a href="http://play.google.com/about/developer-distribution-agreement.html" target="_policies">Developer Distribution Agreement</a></li>
+  </ol>
+</div>
+</div>
+
+<p>
+  Google Play policies prohibit spam, to help ensure the best experience for
+  Android users. Please do not publish deceptive, repetitive, or irrelevant
+  content on Google Play. Not only will it lower your app's rating and cause
+  negative reviews, it can result in your app being suspended or your developer
+  account terminated.
+</p>
+
+<p>
+  As an app developer, it is your responsibility to ensure that your apps are
+  free from spam and conform to the Google Play policies highlighted in this
+  document. Before you publish, make sure that you understand what is
+  considered spam on Google Play and check your apps for violations, even those
+  that might be inadvertent. The sections below highlight best practices and
+  common spam examples to help you avoid the most common types of policy
+  violations.
+</p>
+
+<p>
+  For more information about Google Play policies that apply to your apps and
+  content, please see the <a href=
+  "http://play.google.com/about/developer-content-policy.html" target=
+  "_policies">Developer Program Policies</a> and <a href=
+  "http://play.google.com/about/developer-distribution-agreement.html" target=
+  "_policies">Developer Distribution Agreement</a>.
+</p>
+
+
+<h2 id="keyword-spam">Spam in App Title and Description</h2>
+
+<p>
+  When you publish an app on Google Play, you should pay special attention to
+  the app's title and description in its store listing. Those fields are
+  important because they make your app recognizable to users, and they help to
+  drive downloads by highlighting what's great about your app. A memorable
+  title and compelling description are essential to effective marketing, but
+  you should realize that these must follow Google Play policies, just as your
+  app content must do.
+</p>
+
+<p>
+  Many developers unknowingly violate spam policy in their app titles and
+  descriptions in ways that are easy to avoid. In general, you can
+  avoid spam violations in your app title and description by following these
+  best practices:
+</p>
+
+<ul>
+  <li>
+    <strong>Highlight what's great about your app</strong>&mdash;Share
+    interesting and exciting facts about your app with users. Help users
+    understand what makes your app special.
+  </li>
+
+  <li>
+    <strong>Describe your app accurately</strong>&mdash;Make sure the title
+    and description describe the app function and user experience accurately.
+  </li>
+
+  <li>
+    <strong>Don't use repetitive keywords</strong>&mdash;Avoid keywords that
+    are repetitive or excessive.
+  </li>
+
+  <li>
+    <strong>Don't include unrelated keywords or references</strong> &mdash;
+    Your description should not be loaded with irrelevant keywords in an
+    attempt to manipulate ranking or relevancy.
+  </li>
+
+  <li>
+    <strong>Keep it brief</strong>&mdash;Keep the description succinct and
+    straightforward. Shorter descriptions tend to give a better user experience
+    on devices with smaller displays. Excessive length, detail, or repetition
+    can violate spam policy.
+  </li>
+</ul>
+
+<p>
+  Here's an example app title and description that follows best practices and
+  does not violate Google Play spam policies.
+</p>
+
+<div class="example-block good" style="width:100%;float:none;margin:.5em auto 2em 0;">
+  <div class="heading">Best practice: App description</div>
+  <table>
+  <tr>
+    <td>App Title:</td>
+    <td>Kids puzzle: Identify Turtles</td>
+  </tr>
+  <tr>
+    <td style="white-space:nowrap;">App Description:</td>
+    <td>
+      <p>This is the perfect app to have a good time with your children. It
+        is designed to help kids learn different species of turtles through
+        cute pictures and amusing puzzle games.</p>
+      <p>The rules of Kids puzzle: Identify Turtles are quite simple. Have
+        your child drag images around the screen to fit them into the shaded
+        region. Phonics is also utilized, as a child can also tap the word
+        below the image and hear the name pronounced.</p>
+    </td>
+  </tr>
+  </table>
+</div>
+
+<p>
+  The sections below highlight common types of policy violations in an app
+  title and description, illustrated with variations on the best practice
+  example. 
+</p>
+
+<h3 id="repetitive-keywords">Repetitive keywords</h3>
+
+<p>
+  Your app description should not include keywords that are repetitive or excessive.
+</p>
+
+<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
+  <div class="heading">Description includes repetitive keywords</div>
+  <table>
+  <tr>
+    <td>App Title:</td>
+    <td>Kids puzzle: Identify Turtles</td>
+  </tr>
+  <tr>
+    <td style="white-space:nowrap;">App Description:</td>
+    <td>
+      <p>This is the perfect app to have a good time with your children. It is
+        designed to help kids learn different species of turtles through cute
+        pictures and amusing puzzle games.</p>
+      <p>The rules of Kids puzzle: Identify Turtles are quite simple. Have your
+        child drag images around the screen to fit them into the shaded region.
+        Phonics is also utilized, as a child can also tap the word below the image
+        and hear the name pronounced.</p>
+      <p style="border:2px solid red;">KEYWORDS: game, games, fun, funny, child,
+        children, kid, kids, puzzle, puzzle games, sound, turtle, turtles, sea turtles,
+        turtles, turtle, turtles, tortoise, tortoises, tortoise, tortoise,  turtles,
+        turtles, turtles, turtles, tortoises, tortoise</p>
+    </td>
+  </tr>
+  </table>
+</div>
+
+<h3 id="unrelated-keywords">Unrelated keywords or references</h3>
+
+<p>
+  The description should not be loaded with irrelevant keywords in an attempt
+  to manipulate ranking or relevancy in Google Play search results.
+</p>
+
+<p>
+  For example, if your app has nothing to do with Lady Gaga, then she shouldn’t
+  be included in your description. Also, do not add highly searched, irrelevant
+  keywords that are unrelated to the function of the app. This is in breach of
+  policy.
+</p>
+
+<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
+  <div class="heading">Description includes unrelated keywords or references</div>
+  <table>
+  <tr>
+    <td>App Title:</td>
+    <td>Kids puzzle: Identify Turtles</td>
+  </tr>
+  <tr>
+    <td style="white-space:nowrap;">App Description:</td>
+    <td>
+      <p>This is the perfect app to have a good time with your children. It is designed to
+        help kids learn different species of turtles through cute pictures and amusing puzzle
+        games.</p>
+      <p>The rules of Kids puzzle: Identify Turtles are quite simple. Have your child drag
+        images around the screen to fit them into the shaded region. Phonics is also utilized,
+        as a child can also tap the word below the image and hear the name pronounced.</p>
+      <p style="border:2px solid red;">This game is as addictive as Angry Birds, more social
+        than Facebook and Twitter, and has a soundtrack reminiscent of Katy Perry and Lady
+        Gaga.</p>
+      <p style="border:2px solid red;">KEYWORDS: Angry Birds, Facebook, Twitter, Katy Perry,
+        Lady Gaga</p>
+    </td>
+  </tr>
+  </table>
+</div>
+
+<h3 id="excessive-detail">Excessive detail, references to your other apps</h3>
+
+<p>
+  Your app description should avoid excessive detail and references to your
+  other apps or products. For example, you should not list all of the details
+  of content included in the app or its various components, as shown in the
+  example below. Also, the description should not include any references to
+  other apps you’ve published.
+</p>
+
+<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
+  <div class="heading">Description includes excessive detail, references to your other apps</div>
+  <table>
+  <tr>
+    <td>App Title:</td>
+    <td>Kids puzzle: Identify Turtles</td>
+  </tr>
+  <tr>
+    <td style="white-space:nowrap;">App Description:</td>
+    <td>
+      <p>This is the perfect app to have a good time with your children. It is designed
+        to help kids learn different species of turtles through cute pictures and amusing
+        puzzle games.</p>
+      <p>The rules of Kids puzzle: Identify Turtles are quite simple. Have your child
+        drag images around the screen to fit them into the shaded region. Phonics is also
+        utilized, as a child can also tap the word below the image and hear the name
+        pronounced.</p>
+      <p style="border:2px solid red;">Turtles included in the app: Alligator
+        Snapping Turtle, Asian Box Turtle, Bog Turtle, Common Musk Turtle, Common Snapping
+        Turtle, Diamondback Terrapin, Eastern Box Turtle, Eastern Mud Turtle, Eastern Painted
+        Turtle, False Map Turtle, Florida Pond Cooter, Florida Softshell Turtle, Green Sea
+        Turtle, Map Turtle, Matamata Ornate Box Turtle, Red-bellied Side-necked Turtle,
+        Red-eared Slider, Smooth Softshell Turtle, Spiny Softshell Turtle, Spotted Turtle,
+        Western Painted Turtle, Wood Turtle, Yellow-bellied Slider</p>
+      <p style="border:2px solid red;">If you like this app try our other free apps:<br />
+       ★ Fun Zoo<br />
+       ★ CD Guns<br />
+       ★ Dessert House<br />
+       ★ Playground<br />
+       ★ 578 Weapons</p>
+    </td>
+  </tr>
+  </table>
+</div>
+
+
+<h2 id="ratings">Spam in Ratings and Reviews</h2>
+
+<p>
+  Ratings and reviews are benchmarks of app quality and users depend on them to
+  be authentic and relevant. As an app developer, you should not attempt to
+  artificially influence your app's ratings and reviews or those of your
+  competitor, such as by posting fake ratings or reviews or including spam
+  content in app reviews. The sections below provide guidelines for rating and
+  reviewing apps.
+</p>
+
+<p>
+  So that you can stay in touch with any issues that users are having with your
+  app, you should read through your ratings and reviews on a regular basis. If
+  you choose to reply to reviews, make sure to keep your reply focused on the
+  actual issues raised in the user's comments and do not ask for a higher
+  rating.
+</p>
+
+<p>
+  If you see an app or developer reply that doesn’t follow these guidelines,
+  you can report it. See <a href=
+  "http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=113417&topic=2364761&ctx=topic"
+  target="_policies">Inappropriate content in comments and applications</a> for
+  more information.
+</p>
+
+<div class="example-block bad" style="width:440px;">
+  <div class="heading">Inappropriate content in a review</div>
+  <img src="{@docRoot}images/gp-policy-spam-negreview.png">
+</div>
+
+<div class="example-block bad" style="margin-top:3em;">
+  <div class="heading">Soliciting ratings</div>
+  <img src="{@docRoot}images/gp-policy-spam-reqrating.png">
+</div>
+
+<h3 id="fake-ratings">Fake or inappropriate ratings and reviews</h3>
+
+<p>
+  To help ensure the quality of ratings and reviews, Google Play policies limit
+  the ways that individuals can use ratings and reviews. In particular, note
+  that it is a violation of policy to use ratings and reviews to influence the
+  placement of any app in Google Play.
+</p>
+
+<p>
+  As an app developer, make sure that you follow these guidelines:
+</p>
+
+<ul>
+  <li>
+    <strong>Don't try to manipulate ratings</strong>&mdash;Do not engage in
+    attempts to manipulate the ratings, reviews, or ranking of your apps,
+    either directly or indirectly, or by manipulating the ratings of your
+    competitors. Do not attempt to artificially boost reviews, ratings, or
+    installs through any means.
+  </li>
+
+  <li>
+    <strong>Don't solicit ratings through incentives</strong>&mdash;Do not
+    offer users any incentives to rate your app, such as offering rewards of
+    any kind or tying app functionality to rating.
+  </li>
+
+  <li>
+    <strong>Don't rate apps multiple times</strong>&mdash;Do not review or
+    rate any app multiple times in an attempt to influence its placement in
+    Google Play.
+  </li>
+
+  <li>
+    <strong>Don't add improper content to reviews</strong>&mdash;Do not
+    include affiliate, coupon, game codes, email addresses, or links to
+    websites or other apps in your reviews. If you are responding to a user
+    review, feel free to include references to helpful resources such as a
+    support address or FAQ page.
+  </li>
+</ul>
+
+<h3 id="solicited-ratings">Soliciting ratings from users</h3>
+
+<p>
+  In general, <strong>do not offer incentives for ratings</strong>. You should
+  not offer users incentives of any kind for rating your app (or any other app)
+  on Google Play, and you should not tie your app's functionality or content to
+  rating in any way.
+</p>
+
+<p>
+  It's acceptable to ask users to rate your app without incentives, for
+  example: "If you like this game, rate us in Google Play!" On the other hand,
+  it's a policy violation to ask users to rate your app based on incentives,
+  for example: "Rate this app and get 500 coins" or "Rate this app 5 stars and
+  get you 500 coins!"
+</p>
+
+
+<h2 id="webview-spam" style="clear:right">Spam in WebViews</h2>
+
+<p>
+  Apps published on Google Play should provide their own content. Do not
+  publish an app whose primary function is to reproduce or frame someone else’s
+  website (unless you have permission).
+</p>
+
+<p>
+  Similarly, do not publish an app whose primary function is to drive affiliate
+  traffic to a website. Although affiliate deals can exist where an app's
+  primary purpose is delivering its own content or functionality, it's a
+  violation of Google Play policies to publish an app whose primary (or
+  only) purpose is to direct affiliate traffic to another website.
+</p>
+
+<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
+  <div class="heading">WebView spam</div>
+  <table>
+  <tr>
+    <td>App Title:</td>
+    <td>Kids puzzle: Desktop Browser for Turtoogle Game</td>
+  </tr>
+  <tr>
+    <td>Developer:</td>
+    <td>AAZZZ <span style="border:2px solid red;">(not affiliated with Turtoogle
+      Inc.)</span></td>
+  </tr>
+  <tr>
+    <td style="white-space:nowrap;">App Description:</td>
+    <td>
+      <p>Have you ever wanted to use the full, desktop web version of Turtoogle
+        Game from your phone or tablet instead of the Turtoogle Game mobile app
+        or Turtoogle Game mobile web site?</p>
+      <p style="border:2px solid red;">This app lets you access Turtoogle Game
+        on your Android device in the same way as you access the game on your
+        desktop computer, and with all the same Turtoogle Game features.</p>
+    </td>
+  </tr>
+  </table>
+</div>
+
+
+<h2 id="wizard-spam">Spam from Wizards</h2>
+
+<p>
+  Apps that are created by an automated tool or wizard service must not be
+  submitted to Google Play by the operator of that service on behalf of other
+  persons. Such tools often produce too many duplicative or low-quality
+  apps which crowd the higher-quality apps in the Play Store.
+</p>
+
+<p>
+  Please be advised that apps created by an automated tool are only permissible
+  if the app end-product complies with Google Play policies and is published in
+  the Play Store through a developer account that is registered and owned by
+  you.
+</p>
+
+
+<h2 id="message-spam">Spam in Messaging</h2>
+
+<p>
+  Your app may not send SMS, email, or other messages on behalf of the user
+  without providing the user with the ability to confirm the content and intended
+  recipient.
+</p>
+
+<p>
+  Google Play will aggressively remove applications that are found to send or
+  modify SMS messages without user knowledge or consent.
+</p>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/publish/register.jd b/docs/html/distribute/googleplay/publish/register.jd
index dd73898..5f1f2ea 100644
--- a/docs/html/distribute/googleplay/publish/register.jd
+++ b/docs/html/distribute/googleplay/publish/register.jd
@@ -23,7 +23,7 @@
 
 <ul>
 <li>Register for a Google Play publisher account</li>
-<li>If you will sell apps, set up a Google Checkout Merchant Account</li>
+<li>If you will sell apps, set up a Google Wallet Merchant Account</li>
 <li>Explore the Google Play Developer Console and learn about the tools for publishing</li>
 </ul>
 
@@ -57,11 +57,11 @@
 a Google Checkout account, you can quickly set one up during the process.</li>
 </ol>
 
-<p>When your registration is verified, you’ll be notified at the email address you specified during registration. </p>
+<p>When your registration is verified, you’ll be notified at the email address you specified during registration.</p>
 
-<h3>Set up a Google Checkout Merchant account</h3>
+<h3>Set up a Google Wallet Merchant account</h3>
  
-<p>If you want to sell products on Google Play &mdash; priced apps, in-app products, or subscriptions &mdash; you will also need to set up a Google Checkout <a href="http://checkout.google.com/sell">Merchant Account</a>. You can do that at any time, but make sure to first review the list of <a href="https://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=150324">merchant countries</a>.</p>
+<p>If you want to sell products on Google Play &mdash; priced apps, in-app products, or subscriptions &mdash; you will also need to set up a Google Wallet Merchant Account. You can do that at any time, but make sure to first review the list of <a href="https://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=150324">merchant countries</a>.</p>
 
 <p>To set up a Merchant account from the Developer Console:</p>
 
diff --git a/docs/html/distribute/googleplay/quality/tablet.jd b/docs/html/distribute/googleplay/quality/tablet.jd
index 24a30f1..6d7e3e2 100644
--- a/docs/html/distribute/googleplay/quality/tablet.jd
+++ b/docs/html/distribute/googleplay/quality/tablet.jd
@@ -5,7 +5,7 @@
 <h2>Checklist</h2>
 <ol>
 
-<li><a href="#core-app-quality">1. Test for Core App Quality</a></li>
+<li><a href="#core-app-quality">1. Test for Core Tablet App Quality</a></li>
 <li><a href="#optimize-layouts">2. Optimize your layouts</a></li>
 <li><a href="#use-extra-space">3. Use the extra screen area</a></li>
 <li><a href="#use-tablet-icons">4. Use assets designed for tablets</a></li>
@@ -14,16 +14,17 @@
 <li><a href="#offer-full-feature-set">7. Offer the app's full feature set</a></li>
 <li><a href="#hardware-requirements">8. Don’t require hardware features</a></li>
 <li><a href="#support-screens">9. Declare tablet screen support</a></li>
-<li><a href="#google-play">10. Follow best practices for publishing in Google Play</a></li>
+<li><a href="#google-play">10. Showcase your tablet UI</a></li>
+<li><a href="#google-play-bp">11. Follow publishing best practices</a></li>
 
 </ol>
 <h2>Testing</h2>
 <ol>
+<li><a href="#basic-technical-checks">Basic Technical Checks for Tablets</a></li>
 <li><a href="#test-environment">Setting Up a Test Environment</a></li>
 </ol>
 </div></div>
 
-
 <p>Before you publish an app on Google Play, it's important to make sure that
 the app meets the basic expectations of tablet users through compelling features
 and an intuitive, well-designed UI. </p>
@@ -46,32 +47,81 @@
 that can help you address the topics raised in each task.</p>
 
 
-<h2 id="core-app-quality">1. Test for Core App Quality</h2>
+<h2 id="core-app-quality">1. Test for Core Tablet App Quality</h2>
+
+<p>Before publishing, make sure that your app and it's store listing meet the
+  core quality guidlines below. </p>
+
+<h5>Core app quality</h5>
 
 <p>The first step in delivering a great tablet app experience is making sure
-that it meets the <em>core app
-quality criteria</em> for all of the devices and form factors that the app is
-targeting. For complete information, see the <a
-href="{@docRoot}distribute/googleplay/quality/core.html">Core App Quality Checklist</a>. 
+that it meets the <em>core app quality criteria</em> for all of the devices
+and form factors that the app is targeting. For complete information, see the <a
+href="{@docRoot}distribute/googleplay/quality/core.html">Core App Quality Guidelines</a>. 
 </p>
 
-<p>To assess the quality of your app on tablets &mdash; both for core app quality
-and tablet app quality &mdash; you need to set up a suitable
-hardware or emulator environment for testing. For more information, 
-see <a href="#test-environment">Setting Up a Test Environment</a>.</p>
+<h5>Basic technical checks for tablets</h5>
+<p>
+  Before publishing, you should also ensure that your app passes several basic
+  technical checks, such as:
+</p>
 
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a
-href="{@docRoot}distribute/googleplay/quality/core.html">Core App Quality
-Guidelines</a></strong> &mdash; A set of core quality criteria that all Android
-apps should meet on all targeted devices.</li>
+<ul>
+  <li>Targeting appropriate Android versions</li>
+  <li>Specifying any feature dependencies properly</li>
+  <li>Declaring support for appropriate screens</li>
 </ul>
-</td>
-</tr>
-</table>
+
+<p>
+  For details, see <a href="#basic-technical-checks">Basic Technical
+  Checks</a>.
+</p>
+
+<h5>Tablet screenshots and other promotional tools</h5>
+
+<p>Make sure that you upload screenshots of your tablet UI to the
+  Developer Console and highlight your tablet experience in your app description,
+  video, and promotional campaigns. For details, see <a href="#google-play">Showcase your
+  tablet UI in Google Play.</a></p>
+
+<h5>Test environment</h5>
+
+<p>
+  To assess the quality of your app on tablets, you need to set up a suitable
+  hardware or emulator environment for testing. For more information, see
+  <a href="#test-environment">Setting Up a Test Environment</a>.
+</p>
+<p>
+  Note that a successful tablet app will go <em>well beyond the core and tablet
+  app quality criteria</em> to offer a custom tablet experience to users. Read
+  the sections below for ideas on how to plan and develop a great tablet UI for
+  your app.
+</p>
+
+
+<div class="rel-resources">
+  <h3>
+    Related resources
+  </h3>
+
+  <ul>
+    <li>
+      <a href="{@docRoot}distribute/googleplay/quality/core.html">Core App
+      Quality</a>&mdash;A set of core quality criteria that all Android apps
+      should meet on all targeted devices.
+    </li>
+
+    <li>
+      <a href="#basic-technical-checks">Basic Technical Checks for
+      Tablets</a>&mdash;Additional quality criteria for any app that is
+      targeting, designed for, or distributable to Android tablets.
+    </li>
+    <li>
+      <a href="#google-play">Showcase your tablet UI on Google Play</a>&mdash;Information
+      on how to upload tablet screenshots and promote your tablet app.
+    </li>
+  </ul>
+</div>
 
 <h2 id="optimize-layouts">2. Optimize your layouts for larger screens</h2>
 
@@ -97,9 +147,12 @@
 <p>Here are some suggestions:</p>
 
 <div style="width:390px;float:right;margin:1.5em;margin-top:0em;">
-<img src="{@docRoot}images/training/app-navigation-multiple-sizes-multipane-bad.png" style="width:390px;padding:4px;margin-bottom:0em;">
+<img src="{@docRoot}images/training/app-navigation-multiple-sizes-multipane-bad.png"
+style="width:390px;padding:4px;margin-bottom:0em;">
 <p class="image-caption" style="padding:0em .5em .5em 2em"><span
-style="font-weight:500;">Get rid of "stretched" UI</span>: On tablets, single-pane layouts lead to awkward whitespace and excessive line lengths. Use padding to reduce the width of UI elements and consider using multi-pane layouts.</p>
+style="font-weight:500;">Get rid of "stretched" UI</span>: On tablets, single-pane
+layouts lead to awkward whitespace and excessive line lengths. Use padding to
+reduce the width of UI elements and consider using multi-pane layouts.</p>
 </div>
 
 <ul>
@@ -131,29 +184,51 @@
 multi-pane UI for tablets (see next section).</li>
 </ul>
 
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://developer.android.com/design/style/metrics-grids.html">Metrics and Grids
-</a></strong> &mdash; Android Design document that explains ....</li>
-<li><strong><a href="http://developer.android.com/design/style/devices-displays.html">Devices and Displays
-</a></strong> &mdash; Android Design document that explains ....</li>
-<li><strong><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a></strong> &mdash; Developer documentation that explains the details of managing UI for best display on multiple screen sizes.</li>
-<li><strong><a href="http://developer.android.com/guide/practices/screens_support.html#ConfigurationExamples">Configuration examples
-</a></strong> &mdash; Examples of how to declare layouts and other resources for specific screen sizes.</a></li>
-</ul>
-</td>
-</tr>
-</table>
+<div class="rel-resources">
+  <h3>
+    Related resources
+  </h3>
+
+  <ul>
+    <li>
+      <a href=
+      "{@docRoot}design/style/metrics-grids.html">Metrics
+      and Grids</a>&mdash;Android Design document that explains how to create
+      layouts based on density-independent grids.
+    </li>
+
+    <li>
+      <a href=
+      "{@docRoot}design/style/devices-displays.html">Devices
+      and Displays</a>&mdash;Android Design document that explains how to
+      design a UI that works well on different devices and
+      screen sizes.
+    </li>
+
+    <li>
+      <a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
+      Screens</a>&mdash;Developer documentation that explains the details of
+      managing UI for best display on multiple screen sizes.
+    </li>
+
+    <li>
+      <a href=
+      "{@docRoot}guide/practices/screens_support.html#ConfigurationExamples">
+      Configuration examples</a>&mdash;Examples of how to declare layouts and
+      other resources for specific screen sizes.
+    </li>
+  </ul>
+</div>
 
 
 <h2 id="use-extra-space">3. Take advantage of extra screen area available on tablets</h2>
 
 <div style="width:290px;float:right;margin:1.5em;margin-bottom:0;margin-top:0;">
-<img src="{@docRoot}images/training/app-navigation-multiple-sizes-multipane-good.png" style="width:280px;padding:4px;margin-bottom:0em;">
+<img src="{@docRoot}images/training/app-navigation-multiple-sizes-multipane-good.png"
+style="width:280px;padding:4px;margin-bottom:0em;">
 <p class="image-caption" style="padding:0em .5em .5em 1.5em"><span
-style="font-weight:500;">Multi-pane layouts</span> result in a better visual balance on tablet screens, while offering more utility and legibility.</p>
+style="font-weight:500;">Multi-pane layouts</span> result in a better visual
+balance on tablet screens, while offering more utility and legibility.</p>
 </div>
 
 <p>Tablet screens provide significantly more screen real estate to your app,
@@ -175,39 +250,58 @@
 <li>Plan how you want the panels of your compound views to reorganize when
 screen orientation changes.</li>
 
-
-
 <div style="width:490px;margin:1.5em auto 1.5em 0;">
-
 <div style="">
-<img src="{@docRoot}images/ui-ex-single-panes.png" style="width:490px;padding:4px;margin-bottom:0em;" align="middle">
+<img src="{@docRoot}images/ui-ex-single-panes.png"
+style="width:490px;padding:4px;margin-bottom:0em;" align="middle">
 <img src="{@docRoot}images/ui-ex-multi-pane.png" style="width:490px;padding:4px;margin-bottom:0em;">
 <p class="image-caption" style="padding:.5em"><span
-style="font-weight:500;">Compound views</span> combine several single views from a handset UI <em>(above)</em> into a richer, more efficient UI for tablets <em>(below)</em>. </p>
+style="font-weight:500;">Compound views</span> combine several single views from a
+handset UI <em>(above)</em> into a richer, more efficient UI for tablets
+<em>(below)</em>. </p>
 </div>
 </div>
 
 <li>While a single screen is implemented as an {@link android.app.Activity}
 subclass, consider implementing individual content panels as {@link
-android.app.Fragment} subclasses. This lets you maximize code reuse across
-different form factors and across screens that share content.</li>
+android.app.Fragment} subclasses. This lets you
+maximize code reuse across different form factors and across screens that
+share content.</li>
 <li>Decide on which screen sizes you'll use a multi-pane UI, then provide the
 different layouts in the appropriate screen size buckets (such as
 <code>large</code>/<code>xlarge</code>) or minimum screen widths (such as
 <code>sw600dp</code>/<code>sw720</code>).</li>
 </ul>
 
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}design/patterns/multi-pane-layouts.html">Multi-pane Layouts</a></strong> &mdash; Android Design guide for using multi-pane UI, including examples of how to flatten navigation and integrate more content into your tablet UI.</li>
-<li><strong><a href="{@docRoot}training/design-navigation/multiple-sizes.html">Planning for Multiple Touchscreen Sizes</a></strong> &mdash; Android Training class that walks you through the essentials of planning an intuitive, effective navigation for tablets and other devices. </li>
-<li><strong><a href="{@docRoot}training/multiscreen/index.html">Designing for Multiple Screens</a></strong> &mdash; Android Training class that walks you through the essentials of planning an intuitive, effective navigation for tablets and other devices. </li>
-</ul>
-</td>
-</tr>
-</table>
+<div class="rel-resources">
+  <h3>
+    Related resources
+  </h3>
+
+  <ul>
+    <li>
+      <a href="{@docRoot}design/patterns/multi-pane-layouts.html">Multi-pane
+      Layouts</a>&mdash;Android Design guide for using multi-pane UI, including
+      examples of how to flatten navigation and integrate more content into
+      your tablet UI.
+    </li>
+
+    <li>
+      <a href=
+      "/training/design-navigation/multiple-sizes.html">Planning for Multiple
+      Touchscreen Sizes</a>&mdash;Android Training class that walks you through
+      the essentials of planning an intuitive, effective navigation for tablets
+      and other devices.
+    </li>
+
+    <li>
+      <a href="{@docRoot}training/multiscreen/index.html">Designing for
+      Multiple Screens</a>&mdash;Android Training class that walks you through
+      the essentials of planning an intuitive, effective navigation for tablets
+      and other devices.
+    </li>
+  </ul>
+</div>
 
 
 <h2 id="use-tablet-icons">4. Use Icons and other assets that are designed for tablet screens</h2>
@@ -268,18 +362,41 @@
 gets loaded.</li>
 </ul>
 
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}design/style/iconography.html">Iconography</a></strong> &mdash; Android Design document that shows how to use various types of icons.</li>
-<li><strong><a href="{@docRoot}guide/topics/resources/providing-resources.html">Providing Resources</a></strong> &mdash; Developer documentation on how to provide sets of layouts and drawable resources for specific ranges of device screens. </li>
-<li><strong><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a></strong> &mdash; API Guide documentation that explains the details of managing UI for best display on multiple screen sizes.</li>
-<li><strong><a href="{@docRoot}training/basics/supporting-devices/screens.html">Supporting Different Screens</a></strong> &mdash; Android Training class that takes you through the process of optimizing the user experience for different screen sizes and densities.</li>
-</ul>
-</td>
-</tr>
-</table>
+<div class="rel-resources">
+  <h3>
+    Related resources
+  </h3>
+
+  <ul>
+    <li>
+      <a href="{@docRoot}design/style/iconography.html">Iconography</a>&mdash; Android
+      Design document that shows how to use various types of icons.
+    </li>
+
+    <li>
+      <a href=
+      "/guide/topics/resources/providing-resources.html">Providing
+      Resources</a>&mdash;Developer documentation on how to provide
+      sets of layouts and drawable resources for specific ranges of device
+      screens.
+    </li>
+
+    <li>
+      <a href="{@docRoot}guide/practices/screens_support.html">Supporting
+      Multiple Screens</a>&mdash;API Guide documentation that
+      explains the details of managing UI for best display on multiple screen
+      sizes.
+    </li>
+
+    <li>
+      <a href=
+      "/training/basics/supporting-devices/screens.html">Supporting Different
+      Screens</a>&mdash;Android Training class that takes you
+      through the process of optimizing the user experience for different
+      screen sizes and densities.
+    </li>
+  </ul>
+</div>
 
 
 <h2 id="adjust-font-sizes">5. Adjust font sizes and touch targets for tablet screens</h2>
@@ -300,29 +417,49 @@
 titles, and other elements.</li>
 <li>The recommended touch-target size for onscreen elements is 48dp (32dp
 minimum) &mdash; some adjustments may be needed in your tablet UI. Read <a
-href="http://developer.android.com/design/style/metrics-grids.html">Metrics and
+href="{@docRoot}design/style/metrics-grids.html">Metrics and
 Grids
 </a> to learn about implementation strategies to help most of your users. To
 meet the accessibility needs of certain users, it may be appropriate to use
 larger touch targets. </li>
 <li>When possible, for smaller icons, expand the touchable area to more than
-48dp using {@link android.view.TouchDelegate} or just centering the icon within
-the transparent button.</li>
+48dp using {@link android.view.TouchDelegate}
+or just centering the icon within the transparent button.</li>
 </ul>
 
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://developer.android.com/design/style/metrics-grids.html">Metrics and Grids
-</a></strong> &mdash; Android Design document that explains how to arrange and size touch targets and other UI elements on the screen.</li>
-<li><strong><a href="{@docRoot}design/style/typography.html">Typography</a></strong> &mdash; Android Design document that gives an overview of how to use typography in your apps. </li>
-<li><strong><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a></strong> &mdash; Developer documentation that explains the details of managing UI for best display on multiple screen sizes.</li>
-<li><strong><a href="{@docRoot}training/multiscreen/screendensities.html">Supporting Different Densities</a></strong> &mdash; Android Training class that shows you how to provide sets of layouts and drawable resources for specific ranges of device screens. </li>
-</ul>
-</td>
-</tr>
-</table>
+<div class="rel-resources">
+  <h3>
+    Related resources
+  </h3>
+
+  <ul>
+    <li>
+      <a href=
+      "{@docRoot}design/style/metrics-grids.html">Metrics
+      and Grids</a> &mdash;Android Design document that explains how to arrange
+      and size touch targets and other UI elements on the screen.
+    </li>
+
+    <li>
+      <a href="{@docRoot}design/style/typography.html">Typography</a>&mdash;Android
+      Design document that gives an overview of how to use typography in your
+      apps.
+    </li>
+
+    <li>
+      <a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
+      Screens</a>&mdash;Developer documentation that explains the details of
+      managing UI for best display on multiple screen sizes.
+    </li>
+
+    <li>
+      <a href="{@docRoot}training/multiscreen/screendensities.html">Supporting
+      Different Densities</a>&mdash;Android Training class that shows you how
+      to provide sets of layouts and drawable resources for specific ranges of
+      device screens.
+    </li>
+  </ul>
+</div>
 
 
 <h2 id="adjust-widgets">6. Adjust sizes of home screen widgets for tablet screens</h2>
@@ -343,17 +480,25 @@
 possible.</li>
 </ul>
 
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}guide/topics/appwidgets/index.html#MetaData">Adding the AppWidgetProviderInfo Metadata
-</a></strong> &mdash; API Guide that explains how to set the height and width dimensions of a widget.</li>
-<li><strong><a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget Design Guidelines</a></strong> &mdash; API Guide that provides best practices and techniques for designing and managing the size of widgets.  </li>
-</ul>
-</td>
-</tr>
-</table>
+<div class="rel-resources">
+  <h3>
+    Related resources
+  </h3>
+
+  <ul>
+    <li>
+      <a href="{@docRoot}guide/topics/appwidgets/index.html#MetaData">Adding the
+      AppWidgetProviderInfo Metadata</a> &mdash;API Guide that explains how to
+      set the height and width dimensions of a widget.
+    </li>
+
+    <li>
+      <a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget
+      Design Guidelines</a>&mdash;API Guide that provides best practices and
+      techniques for designing and managing the size of widgets.
+    </li>
+  </ul>
+</div>
 
 
 <h2 id="offer-full-feature-set">7. Offer the app's full feature set to tablet users</h2>
@@ -383,7 +528,8 @@
 </ul>
 
 
-<h2 id="hardware-requirements">8. Don’t require hardware features that might not be available on tablets</h2>
+<h2 id="hardware-requirements">8. Don’t require hardware features that might not be
+  available on tablets</h2>
 
 <p>Handsets and tablets typically offer slightly different hardware support for
 sensors, camera, telephony, and other features. For example, many tablets are
@@ -412,27 +558,46 @@
 href="{@docRoot}guide/topics/manifest/uses-feature-element.html#permissions">imply
 feature requirements</a> that might not be appropriate for tablets, except when
 accompanied by a corresponding <code>&lt;uses-feature&gt;</code> element
-declared with the <code>android:required=”false”</code> attribute.</li>
+declared with the <code>android:required=”false”</code> attribute.
+<p>Here's an example of a dependency that's properly declared as "not required", so that 
+it does not limit distribution to devices that do not support the dependency:</p>
+<p><code>&lt;uses-feature android:name="android.hardware.telephony"
+android:required="false" /&gt;</code></p></li>
 </ul>
 
 <p>In all cases, the app must function normally when the hardware features it
-uses are not available and should offer “graceful degradation” and alternative
+uses are not available and should offer "graceful degradation" and alternative
 functionality where appropriate. For example, if GPS is not supported on the device,
 your app could let the user set their location manually. The app should do
 run-time checking for the hardware capability that it needs and handle as needed.</p>
 
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#permissions">Permissions that Imply Feature Requirements</a></strong> &mdash; A list of permissions that may cause unwanted filtering if declared in your app's manifest.</li>
-<li><strong><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><code>&lt;uses-feature&gt;</code></a></strong> &mdash; Description and reference documentation for the <code>&lt;uses-feature&gt;</code> manifest element.</li>
-<li><strong><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#testing">Testing the features required by your application</a></strong> &mdash; Description of how to determine the actual set of hardware and software requirements (explicit or implied) that your app requires.</li>
-</ul>
-</td>
-</tr>
-</table>
+<div class="rel-resources">
+<h3>
+  Related resources
+</h3>
 
+<ul>
+  <li>
+    <a href=
+    "/guide/topics/manifest/uses-feature-element.html#permissions">Permissions
+    that Imply Feature Requirements</a>&mdash;A list of permissions that may
+    cause unwanted filtering if declared in your app's manifest.
+  </li>
+  <li>
+    <a href=
+    "/guide/topics/manifest/uses-feature-element.html"><code>&lt;uses-feature&gt;</code></a>&mdash;Description
+    and reference documentation for the <code>&lt;uses-feature&gt;</code>
+    manifest element.
+  </li>
+
+  <li>
+    <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#testing">Testing
+    the features required by your application</a>&mdash;Description of how to
+    determine the actual set of hardware and software requirements (explicit or
+    implied) that your app requires.
+  </li>
+</ul>
+</div>
 
 <h2 id="support-screens">9. Declare support for tablet screen configurations</h2>
 
@@ -442,77 +607,441 @@
 <ul>
 <li>Declare a <a
 href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><code>&lt;supports-screens&gt;</code></a> element
-with appropriate attributes, as needed.</li>
+with appropriate attributes, as needed. For details, see <a 
+href="#basic-technical-checks">Basic Technical Checks</a>
+later in this document.</li>
 <li>If the app declares a <code>&lt;compatible-screens&gt;</code> element in the
 manifest, the element must include attributes that specify <em>all of the size and
 density combinations for tablet screens</em> that the app supports. Note that, if possible,
 you should avoid using this element in your app.</li>
 </ul>
 
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><code>&lt;supports-screens&gt;</code></a></strong>
-&mdash; Description and reference documentation for the <code>&lt;supports-screens&gt;</code>
-manifest element.</li>
-<li><strong><a href="{@docRoot}guide/practices/screens_support.html#DeclaringScreenSizeSupport">Declaring Screen Size
-Support</a></strong> &mdash; Developer documentation that explains the details of managing UI
-for best display on multiple screen sizes.</li>
+<div class="rel-resources">
+  <h3>
+    Related resources
+  </h3>
+
+  <ul>
+    <li>
+      <a href="#basic-technical-checks">Basic Technical
+      Checks</a>&mdash;Includes details (see <a href="#TB-R4">TB-R4</a>) on how
+      to properly declare screens support for tablet screen sizes.
+    </li>
+
+    <li>
+      <a href=
+      "/guide/topics/manifest/supports-screens-element.html"><code>&lt;supports-screens&gt;</code></a>&mdash;Description
+      and reference documentation for the <code>&lt;supports-screens&gt;</code>
+      manifest element.
+    </li>
+
+    <li>
+      <a href=
+      "/guide/practices/screens_support.html#DeclaringScreenSizeSupport">Declaring
+      Screen Size Support</a>&mdash;Developer documentation that explains the
+      details of managing UI for best display on multiple screen sizes.
+    </li>
+  </ul>
+</div>
+
+
+<h2 id="google-play">10. Showcase your tablet UI in Google Play</h2>
+
+<p>
+  After you've done the work to create an rich, optimized UI for your tablet
+  app, make sure that you let your customers know about it! Here are some key
+  ways to promote your tablet app to users on Google Play.
+</p>
+
+<h5>
+  Upload screenshots of your tablet UI
+</h5>
+
+<p>
+  Tablet users want to know what your app is like on a tablet device, not on a
+  phone. Capitalize on their interest by showing them screenshots of your
+  tablet UI on your app's store listing page. You can upload tablet screenshots
+  from the Developer Console. Here are some tips and guidelines:
+</p>
+
+<ul style="margin-top:0;">
+  <li>Your screenshots should show the core functionality of your app, not a
+  startup or sign-in page. Wherever users will spend most of their time, that's
+  what you should show in your screenshots.
+  </li>
+
+  <li>Add screenshots taken on both 7-inch and 10-inch tablets, if possible.
+  </li>
+
+  <li>It's recommended that you add screenshots taken in both landscape and
+  portrait orientations, if possible.
+  </li>
+
+  <li>Use screen captures if possible. Avoid showing actual device hardware in your
+  screenshots.</li>
+
+  <li>The recommended resolution of your tablet screenshots is <strong>1280 x 720</strong>
+  or higher in each orientation.
+  </li>
+
+  <li>You can upload as many as 8 screenshots of your tablet UI for 7-inch tablets
+  and an additional 8 for 10-inch tablets.
+  </li>
 </ul>
-</td>
-</tr>
-</table>
 
-
-<h2 id="google-play">10. Follow best practices for publishing in Google Play</h2>
+<h5>
+  Update your app description and release notes
+</h5>
 
 <ul>
-<li>Publish your app as a single APK for all screen sizes (handsets
-and tablets), with a single Google Play listing:
-  <ul style="margin-top:.25em;">
-    <li>Easier for users to find your app from search, browsing, or promotions</li>
-    <li>Easier for users to restore your app automatically if they get a new device.</li>
-    <li>Your ratings and download stats are consolidated across all devices.</li>
-    <li>Publishing a tablet app in a second listing can dilute ratings for your brand.</li>
-  </ul>
-</li>
-<li>If necessary, you can alternatively choose to deliver your app using <a 
-href="{@docRoot}google/play/publishing/multiple-apks.html">Multiple APK Support</a>, 
-although in most cases using a single APK to reach all devices is strongly recommended.</li>
+  <li>In your app description, make sure to highlight that your app offers
+  tablet-optimized UI and great features for tablet users. Consider adding some
+  detail about how your tablet UI works and why users will like it.
+  </li>
 
-<li>Highlight your app’s tablet capabilities in the product details page:
-  <ul style="margin-top:.25em;">
-    <li>Add <strong>at least one screenshot taken while the app is running on a
-    tablet</strong>. It's recommended that you add one screenshot of landscape orientation
-    and one of portrait orientation, if possible. These screenshots make it clear to users
-    that your app is designed for tablets and highlight all the effort you've put into designing
-    a great tablet app experience.</li>
-    <li>Mention tablet support in the app description.</li>
-    <li>Include information about tablet support in the app's release notes and update
-    information.</li>
-    <li>In your app's promo video, add shots of your app running on a tablet.</li>
-  </ul>
-</li>
-<li>Make sure you are distributing to tablet devices. Check the app's Supported Devices
-list in the <a href="https://play.google.com/apps/publish/">Developer Console</a>
-to make sure your app is not filtered from tablet devices that you want to target.</li>
-
-<li>Let tablet users know about your app! Plan a marketing or advertising campaign that
-highlights the use of your app on tablets.</li>
+  <li>Include information about tablet support in the app's release notes and
+  update information.
+  </li>
 </ul>
 
+<h5>
+  Update your promotional video
+</h5>
+
+<p>
+  Many users view an app's promotional video to get an idea of what the app is
+  like and whether they'll enjoy it. For tablet users, capitalize on this
+  interest by highlighting your app's tablet UI in your promotional video. Here
+  are some tips and guidelines:
+</p>
+
+<ul>
+  <li>Add one or more shots of your app running on a tablet. To engage with
+  tablet users most effectively, it's recommended that you promote your tablet
+  UI in approximately equal proportion to your phone UI.
+  </li>
+
+  <li>Show your tablet UI as early as possible in the video. Don't assume that
+  tablet users will wait patiently through a feature walkthrough on a phone UI.
+  Ideally, you should engage them immediately by showing the tablet UI within
+  the first 10 seconds, or at the same point that you introduce the phone UI.
+  </li>
+
+  <li>To make it clear that you are showing a tablet UI, include shots of your
+  app running on a hand-held tablet device.
+  </li>
+
+  <li>Highlight your app's tablet UI in the video's narrative or voiceover.
+  </li>
+</ul>
+
+<h5>
+  Feature your tablet UI in your promotional campaigns
+</h5>
+
+<p>
+  Make sure to let tablet users know about your tablet UI in your promotional
+  campaigns, web site, social posts, advertisements, and elsewhere. Here are
+  some suggestions:
+</p>
+
+<ul>
+  <li>Plan a marketing or advertising campaign that highlights the use of your
+  app on tablets.</li>
+
+  <li>Show your tablet app at its best in your promotional campaigns&mdash;use the <a href=
+  "{@docRoot}distribute/promote/device-art.html">Device Art Generator</a> to
+  quickly generate a high-quality promotional image of your app running on a
+  7-inch or 10-inch tablet, in the orientation of your choice, with or without
+  drop-shadow and screen glare. It's as simple as capture, drag, and drop.
+  </li>
+
+  <li>Include a Google Play badge in your online promotions to let users link
+  directly to your app's store listing. You can generate a badge in a variety
+  of languages using the <a href=
+  "{@docRoot}distribute/googleplay/promote/badges.html">Badge Generator</a>.
+  </li>
+</ul>
+
+<div class="rel-resources">
+  <h3>
+    Related resources
+  </h3>
+
+  <ul>
+    <li>
+      <a href="{@docRoot}distribute/googleplay/publish/preparing.html">Publishing
+      Checklist</a>
+      &mdash;Recommendations on how to prepare your app for publishing, test
+      it, and launch successfully on Google Play.
+    </li>
+
+    <li>
+      <a href="https://play.google.com/apps/publish/">Google Play
+      Developer Console</a>&mdash;The tools console for publishing
+      your app to Android users.
+    </li>
+    <li>
+      <a href=
+      "{@docRoot}distribute/googleplay/promote/badges.html">Google Play
+      Badge Generator</a>&mdash;Create "Get it on Google Play" badges for your
+      app in a variety of languages with a single click. 
+    </li>
+    <li>
+      <a href=
+      "{@docRoot}distribute/googleplay/promote/device-art.html">Device Art
+      Generator</a>&mdash;Drag and drop tool that lets you instantly create production-
+      ready art showing your app running on a tablet device. 
+    </li>
+  </ul>
+</div>
+
+<h2 id="google-play-bp">11. Follow best practices for publishing in Google Play</h2>
+
+<p>Make sure that your app follows key best practices that ensure broad
+  distribution to tablet devices. </p>
+
+<h5>Verify basic technical checks</h5>
+
+  <ul>
+    <li>Verify that the app is targeting the proper Android versions and screen sizes 
+    for Android tablets. Follow the <a href="#basic-technical-checks">Basic Technical
+    Checks for Tablets</a> listed in the next section. </li>
+    <li>After you've uploaded the app to the 
+    <a href="https://play.google.com/apps/publish/">Developer Console</a>,
+    check the APK's Supported Devices list to make sure that the app is not filtered
+    from tablet devices that you want to target.</p></li>
+  </ul>
+
+<h5>
+  Distribute as a single APK
+</h5>
+
+<p>
+  It's recommended that you publish your app as a single APK for all screen
+  sizes (phones and tablets), with a single Google Play listing. This approach
+  has several important advantages.
+</p>
+
+<ul style="margin-top:.25em;">
+  <li>Easier for users to find your app from search, browsing, or promotions
+  </li>
+
+  <li>Easier for users to restore your app automatically if they get a new
+  device.
+  </li>
+
+  <li>Your ratings and download stats are consolidated across all devices.
+  </li>
+
+  <li>Publishing a tablet app in a second listing can dilute ratings for your
+  brand.
+  </li>
+</ul>
+
+<p>
+  If necessary, you can alternatively choose to deliver your app using <a href=
+  "/google/play/publishing/multiple-apks.html">Multiple APK Support</a>,
+  although in most cases using a single APK to reach all devices is strongly
+  recommended.
+</p>
+
+<div class="rel-resources">
+<h3>Related resources</h3>
+<ul>
+<li><a href="{@docRoot}distribute/googleplay/publish/preparing.html">Publishing
+      Checklist</a>&mdash;
+  Recommendations on how to prepare your app for publishing, test it, and launch
+  successfully on Google Play.</li>
+<li><a href="https://play.google.com/apps/publish/">Google Play Developer
+  Console</a>&mdash;The tools console for publishing your app to Android users.</li>
+</ul>
+</div>
+
+<h2 id="basic-technical-checks">Basic Technical Checks for Tablets</h2>
+
+<p>
+  This section lists specific details on basic technical checks that you should
+  perform before publishing. The checks ensure that your app is properly targeted to a
+  broad range of tablet devices. Make sure that the app meets all of the checks
+  listed below.
+</p>
+
+<p>
+  To verify the basic technical checks, follow the <a href="#tests">Test
+  Procedures</a> listed below. Before you start, you need to obtain need the
+  application source code.
+</p>
+
+<h5 id="criteria">
+Technical checks
+</h5>
+
 <table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="https://play.google.com/apps/publish/">Publishing Checklist</a></strong> &mdash; Recommendations on how to prepare your app for publishing, test it, and launch successfully on Google Play.</li>
-<li><strong><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></strong> &mdash; The tools console for publishing your app to Android users.</li>
-</ul>
-</td>
-</tr>
+  <tr>
+    <th style="width:2px;">
+      Area
+    </th>
+    <th style="width:54px;">
+      ID
+    </th>
+    <th>
+      Description
+    </th>
+    <th style="width:54px;">
+      Tests
+    </th>
+  </tr>
+  <tr id="TB-R1">
+    <td rowspan="2">Android Versions</td>
+    <td>
+      TB-R1
+    </td>
+    <td>
+      <p style="margin-bottom:.5em;">App <em>does</em> target minimum Android versions
+        that support tablets:</p>
+      <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+        <li><code>targetSdkVersion</code> is declared with value 11 or higher, OR</li>
+        <li><code>minSdkVersion</code> is declared with value 11 or higher.</li>
+      </ol>
+    </td>
+      <td><a href="#tests">TA-1</a></td>
+  </tr>
+  <tr id="TB-R2">
+    <td>
+      TB-R2
+    </td>
+    <td>
+      <p style="margin-bottom:.5em;">App <em>does not</em> limit targeting to
+        exclude Android versions that support tablets:</p>
+      <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+        <li><code>maxSdkVersion</code>, if declared, must have a value of 12
+          or higher. </li>
+      </ol>
+      <p class="caution" style="margin-bottom:.25em;">Note that, in most cases, the use of <code>
+        maxSdkVersion</code> is not recommended.</p>
+    </td>
+    <td><a href="#tests">TA-1</a></td>
+  </tr>
+  <tr id="TB-R3">
+    <td rowspan="1">Feature Dependencies</td>
+    <td>
+      TB-R3
+    </td>
+    <td>
+      <p style="margin-bottom:.5em;">App <em>does not</em> limit distribution to
+        tablets by requiring hardware features not normally available on tablets,
+        whether <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#declared"
+        declared explicitly</a> or <a href=
+        "/guide/topics/manifest/uses-feature-element.html#permissions">implied by
+        permissions</a>.
+      </p> 
+      <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+        <li>the app must not declare a <code>&lt;uses-feature&gt;</code> element for
+          <code>android.hardware.telephony</code> unless the element is specifically
+          marked with the <code>android:required="false"</code> attribute. 
+        </li>
+      </ol>
+      <p>For details, see <a href="#hardware-requirements">Hardware Requirements</a>
+        earlier in this document.</p>
+    </td>
+    <td><a href="#tests">TA-1</a></td>
+  </tr>
+  <tr id="TB-R4">
+  <td rowspan="2">Screens Support</td>
+    <td>
+      TB-R4
+    </td>
+    <td>
+      <p style="margin-bottom:.5em;">App <em>does not</em> limit distribution to common
+        tablet screen sizes:</p>
+      <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+        <li>If declared, <code>&lt;supports-screens&gt;</code> element must not specify
+          <code>android:largeScreens="false"</code> or <code>android:xlargeScreens="false"</code>.</li>
+        <li>For a <code>minSdkVersion</code> value less than 13, a <code>&lt;supports-screens&gt;</code>
+          element must be declared with both <code>android:largeScreens="true"</code>
+          and <code>android:xlargeScreens="true"</code>.</li>
+      </ol>
+    </td>
+    <td><a href="#tests">TA-1</a></td>
+  </tr>
+  <tr id="TB-R5">
+    <td>
+          TB-R5
+    </td>
+    <td>
+      <p style="margin-bottom:.5em;">App <em>does</em> supply custom drawables and
+        assets for common tablet screen densities. Specifically, the APK must include
+        corresponding resource directories tagged with these qualifiers:</p>
+        <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+            <li>An <code>hdpi</code> qualifier, OR</li>
+            <li>An <code>xhdpi</code> qualifier, OR</li>
+            <li>An <code>xxhdpi</code> qualifier</li>
+          </ol>
+
+          <p>For details, see <a href="#use-tablet-icons">Icons and Other Assets</a>
+            earlier in this document.</p>
+      </td>
+    <td><a href="#tests">TA-2</a></td>
+  </tr>
 </table>
 
+<p>If you use <a href="{@docRoot}google/play/publishing/multiple-apks.html">multiple APK
+  support</a> to deliver size- or version-specific APKs, the APKs and their
+  characteristics must meet all of the criteria listed above, either individually
+  or as a cumulative set.</p>
+
+<h5 id="tests">
+  Test procedures
+</h5>
+
+<table>
+  <tr>
+    <th style="width:54px;">
+      Procedure
+    <th>
+      Description
+    </th>
+  </tr>
+    <td>
+         TA-1
+   </td>
+    <td>
+      <p style="margin-bottom:.5em;">Obtain the APK and inspect the manifest.xml file. Check for the required attribute values.</p>
+    </td>
+  </tr>
+  <tr id="ta2">
+    <td>
+      TA-2
+    </td>
+    <td>
+      <p style="margin-bottom:.5em;">Obtain the APK and inspect the resources
+        directories. Make sure that the app includes custom drawables and assets
+        directories tagged with the required qualifiers.</p>
+      </td>
+  </tr>
+</table>
+
+<div class="rel-resources">
+  <h3>
+    Related resources
+  </h3>
+
+  <ul>
+    <li>
+      <a href="{@docRoot}distribute/googleplay/quality/core.html">Core App
+      Quality</a>&mdash;A set of core quality criteria that all Android apps
+      should meet on all targeted devices.
+    </li>
+
+    <li>
+      <a href="#test-environment">Setting up a Test
+      Environment</a>&mdash;Information on how to set up an environment to test
+      your app on tablets.
+    </li>
+  </ul>
+</div>
+
 <h2 id="test-environment">Setting Up a Test Environment for Tablets</h2>
 
 <p>To assess the quality of your app on tablets &mdash; both for core app quality
@@ -541,7 +1070,7 @@
 
 <p class="table-caption"><strong>Table 1</strong>. A typical tablet test environment might
 include one or two devices from each row in the table below, with one of the
-listed chipsets, platform versions, and hardware feature configurations.</p>
+listed platform versions, screen configurations, and hardware feature configurations.</p>
 
 <table>
 <tr>
@@ -556,14 +1085,14 @@
 <td>7-inch tablet</td>
 <td><span style="white-space:nowrap"><code>large</code> or</span><br /><code>-sw600</code></td>
 <td><code>hdpi</code>,<br /><code>tvdpi</code></td>
-<td>Android 4.0+</td>
+<td>Android 4.0+ (API level 14 and higher)</td>
 <td>WXGA800-7in</td>
 </tr>
 <tr>
 <td><span style="white-space:nowrap">10-inch</span> tablet</td>
 <td><span style="white-space:nowrap"><code>xlarge</code> or</span><br /><code>-sw800</code></td>
-<td><code>mdpi</code>,<br /><code>hdpi</code></td>
-<td>Android 3.2+</td>
+<td><code>mdpi</code>,<br /><code>hdpi</code>,<br /><code>xhdpi</code></td>
+<td>Android 3.2+ (API level 13 and higher)</td>
 <td>WXGA800</td>
 </tr>
 </table>
\ No newline at end of file
diff --git a/docs/html/images/example-bad.png b/docs/html/images/example-bad.png
new file mode 100644
index 0000000..b19a9f7
--- /dev/null
+++ b/docs/html/images/example-bad.png
Binary files differ
diff --git a/docs/html/images/example-good.png b/docs/html/images/example-good.png
new file mode 100644
index 0000000..6bd2408
--- /dev/null
+++ b/docs/html/images/example-good.png
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-eula-violation.png b/docs/html/images/gp-policy-ads-eula-violation.png
new file mode 100644
index 0000000..e8ffa5b
--- /dev/null
+++ b/docs/html/images/gp-policy-ads-eula-violation.png
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-eula.png b/docs/html/images/gp-policy-ads-eula.png
new file mode 100644
index 0000000..68a6b95
--- /dev/null
+++ b/docs/html/images/gp-policy-ads-eula.png
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-impersonate-violation.png b/docs/html/images/gp-policy-ads-impersonate-violation.png
new file mode 100644
index 0000000..385ae6e
--- /dev/null
+++ b/docs/html/images/gp-policy-ads-impersonate-violation.png
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-maturity-violation.png b/docs/html/images/gp-policy-ads-maturity-violation.png
new file mode 100644
index 0000000..d41870e
--- /dev/null
+++ b/docs/html/images/gp-policy-ads-maturity-violation.png
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-notif-attr-violation.png b/docs/html/images/gp-policy-ads-notif-attr-violation.png
new file mode 100644
index 0000000..af53f10
--- /dev/null
+++ b/docs/html/images/gp-policy-ads-notif-attr-violation.png
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-notif-attr.png b/docs/html/images/gp-policy-ads-notif-attr.png
new file mode 100644
index 0000000..4934d21
--- /dev/null
+++ b/docs/html/images/gp-policy-ads-notif-attr.png
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-paywall-violation.png b/docs/html/images/gp-policy-ads-paywall-violation.png
new file mode 100644
index 0000000..8bbfd1b
--- /dev/null
+++ b/docs/html/images/gp-policy-ads-paywall-violation.png
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-paywall.png b/docs/html/images/gp-policy-ads-paywall.png
new file mode 100644
index 0000000..e7b1e19
--- /dev/null
+++ b/docs/html/images/gp-policy-ads-paywall.png
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-terms.png b/docs/html/images/gp-policy-ads-terms.png
new file mode 100644
index 0000000..dcbdf4a
--- /dev/null
+++ b/docs/html/images/gp-policy-ads-terms.png
Binary files differ
diff --git a/docs/html/images/gp-policy-ip-copyright-violation.png b/docs/html/images/gp-policy-ip-copyright-violation.png
new file mode 100644
index 0000000..a4e96a8
--- /dev/null
+++ b/docs/html/images/gp-policy-ip-copyright-violation.png
Binary files differ
diff --git a/docs/html/images/gp-policy-ip-impersonation-violation.png b/docs/html/images/gp-policy-ip-impersonation-violation.png
new file mode 100644
index 0000000..b1d9923
--- /dev/null
+++ b/docs/html/images/gp-policy-ip-impersonation-violation.png
Binary files differ
diff --git a/docs/html/images/gp-policy-ip-trademark-violation.png b/docs/html/images/gp-policy-ip-trademark-violation.png
new file mode 100644
index 0000000..c05b67b
--- /dev/null
+++ b/docs/html/images/gp-policy-ip-trademark-violation.png
Binary files differ
diff --git a/docs/html/images/gp-policy-spam-negreview.png b/docs/html/images/gp-policy-spam-negreview.png
new file mode 100644
index 0000000..f68eba3
--- /dev/null
+++ b/docs/html/images/gp-policy-spam-negreview.png
Binary files differ
diff --git a/docs/html/images/gp-policy-spam-reqrating.png b/docs/html/images/gp-policy-spam-reqrating.png
new file mode 100644
index 0000000..aaf9e53
--- /dev/null
+++ b/docs/html/images/gp-policy-spam-reqrating.png
Binary files differ
diff --git a/docs/html/support.jd b/docs/html/support.jd
index 89acd5d..86427b4 100644
--- a/docs/html/support.jd
+++ b/docs/html/support.jd
@@ -46,7 +46,7 @@
 
 <h5 id="contact">Direct support contacts for developers</h5>
 <p style="color:#888">
-  <a href="http://support.google.com/googleplay/android-developer/bin/request.py?contact_type=dev_registration">Registration, account issues</a><br />
+  <a href=" https://support.google.com/googleplay/android-developer/troubleshooter/3049653">Registration, account issues</a><br />
   <a href="http://support.google.com/googleplay/android-developer/bin/request.py?contact_type=publishing">Publishing, app distribution issues</a><br />
   <a href="http://support.google.com/googleplay/android-developer/bin/request.py?contact_type=bugs">Developer Console issues</a><br />
   <a href="http://support.google.com/googleplay/android-developer/bin/request.py?contact_type=takedown">Inappropriate apps</a><br />
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 45385ee..fb5e039 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -103,14 +103,6 @@
         }
     }
 
-    public boolean put(String key, byte[] value, int uid) {
-        return put(key, value, uid, FLAG_ENCRYPTED);
-    }
-
-    public boolean put(String key, byte[] value) {
-        return put(key, value, UID_SELF);
-    }
-
     public boolean delete(String key, int uid) {
         try {
             return mBinder.del(key, uid) == NO_ERROR;
@@ -205,14 +197,6 @@
         }
     }
 
-    public boolean generate(String key, int uid) {
-        return generate(key, uid, FLAG_ENCRYPTED);
-    }
-
-    public boolean generate(String key) {
-        return generate(key, UID_SELF);
-    }
-
     public boolean importKey(String keyName, byte[] key, int uid, int flags) {
         try {
             return mBinder.import_key(keyName, key, uid, flags) == NO_ERROR;
@@ -222,14 +206,6 @@
         }
     }
 
-    public boolean importKey(String keyName, byte[] key, int uid) {
-        return importKey(keyName, key, uid, FLAG_ENCRYPTED);
-    }
-
-    public boolean importKey(String keyName, byte[] key) {
-        return importKey(keyName, key, UID_SELF);
-    }
-
     public byte[] getPubkey(String key) {
         try {
             return mBinder.get_pubkey(key);
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index e0d96c9..b08c36b 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -33,7 +33,9 @@
 #include <utils/threads.h>
 #include <utils/Timers.h>
 #include <utils/ZipFileRO.h>
+#ifdef HAVE_ANDROID_OS
 #include <cutils/trace.h>
+#endif
 
 #include <assert.h>
 #include <dirent.h>
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 910f3e7..281f9a5 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -60,14 +60,14 @@
 	LOCAL_MODULE := libhwui
 	LOCAL_MODULE_TAGS := optional
 
-        ifneq (false,$(ANDROID_ENABLE_RENDERSCRIPT))
-            LOCAL_CFLAGS += -DANDROID_ENABLE_RENDERSCRIPT
-            LOCAL_SHARED_LIBRARIES += libRS libRScpp
-            LOCAL_C_INCLUDES += \
-		$(intermediates) \
-		frameworks/rs/cpp \
-		frameworks/rs
-        endif
+	ifneq (false,$(ANDROID_ENABLE_RENDERSCRIPT))
+		LOCAL_CFLAGS += -DANDROID_ENABLE_RENDERSCRIPT
+		LOCAL_SHARED_LIBRARIES += libRS libRScpp
+		LOCAL_C_INCLUDES += \
+			$(intermediates) \
+			frameworks/rs/cpp \
+			frameworks/rs
+	endif
 
 	ifndef HWUI_COMPILE_SYMBOLS
 		LOCAL_CFLAGS += -fvisibility=hidden
diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
index 46beb94..790c4f4 100644
--- a/libs/hwui/Debug.h
+++ b/libs/hwui/Debug.h
@@ -84,6 +84,9 @@
 // Turn on to insert an event marker for each display list op
 #define DEBUG_DISPLAY_LIST_OPS_AS_EVENTS 0
 
+// Turn on to highlight drawing batches and merged batches with different colors
+#define DEBUG_MERGE_BEHAVIOR 0
+
 #if DEBUG_INIT
     #define INIT_LOGD(...) ALOGD(__VA_ARGS__)
 #else
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index d5007e1..f0084f2 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -23,6 +23,7 @@
 
 #include "Caches.h"
 #include "Debug.h"
+#include "DeferredDisplayList.h"
 #include "DisplayListOp.h"
 #include "OpenGLRenderer.h"
 
@@ -38,15 +39,27 @@
 // Depth of the save stack at the beginning of batch playback at flush time
 #define FLUSH_SAVE_STACK_DEPTH 2
 
+#define DEBUG_COLOR_BARRIER          0x1f000000
+#define DEBUG_COLOR_MERGEDBATCH      0x5f7f7fff
+#define DEBUG_COLOR_MERGEDBATCH_SOLO 0x5f7fff7f
+
 /////////////////////////////////////////////////////////////////////////////////
 // Operation Batches
 /////////////////////////////////////////////////////////////////////////////////
 
-class DrawOpBatch {
+class Batch {
 public:
-    DrawOpBatch() { mOps.clear(); }
+    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) = 0;
+    virtual ~Batch() {}
+};
 
-    virtual ~DrawOpBatch() { mOps.clear(); }
+class DrawBatch : public Batch {
+public:
+    DrawBatch(int batchId, mergeid_t mergeId) : mBatchId(batchId), mMergeId(mergeId) {
+        mOps.clear();
+    }
+
+    virtual ~DrawBatch() { mOps.clear(); }
 
     void add(DrawOp* op) {
         // NOTE: ignore empty bounds special case, since we don't merge across those ops
@@ -54,7 +67,7 @@
         mOps.add(op);
     }
 
-    virtual bool intersects(Rect& rect) {
+    bool intersects(Rect& rect) {
         if (!rect.intersects(mBounds)) return false;
 
         for (unsigned int i = 0; i < mOps.size(); i++) {
@@ -71,8 +84,9 @@
         return false;
     }
 
-    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty) {
-        DEFER_LOGD("replaying draw batch %p", this);
+    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
+        DEFER_LOGD("%d  replaying DrawingBatch %p, with %d ops (batch id %x, merge id %p)",
+                index, this, mOps.size(), mOps[0]->getBatchId(), mOps[0]->getMergeId());
 
         status_t status = DrawGlInfo::kStatusDone;
         DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
@@ -84,31 +98,127 @@
 #if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
             renderer.eventMark(op->name());
 #endif
-            status |= op->applyDraw(renderer, dirty, 0);
+            status |= op->applyDraw(renderer, dirty);
             logBuffer.writeCommand(0, op->name());
+
+#if DEBUG_MERGE_BEHAVIOR
+            Rect& bounds = mOps[i]->state.mBounds;
+            int batchColor = 0x1f000000;
+            if (getBatchId() & 0x1) batchColor |= 0x0000ff;
+            if (getBatchId() & 0x2) batchColor |= 0x00ff00;
+            if (getBatchId() & 0x4) batchColor |= 0xff0000;
+            renderer.drawScreenSpaceColorRect(bounds.left, bounds.top, bounds.right, bounds.bottom,
+                    batchColor);
+#endif
         }
         return status;
     }
 
+    inline int getBatchId() const { return mBatchId; }
+    inline mergeid_t getMergeId() const { return mMergeId; }
     inline int count() const { return mOps.size(); }
-private:
+
+protected:
     Vector<DrawOp*> mOps;
     Rect mBounds;
+private:
+    int mBatchId;
+    mergeid_t mMergeId;
 };
 
-class StateOpBatch : public DrawOpBatch {
+// compare alphas approximately, with a small margin
+#define NEQ_FALPHA(lhs, rhs) \
+        fabs((float)lhs - (float)rhs) > 0.001f
+
+class MergingDrawBatch : public DrawBatch {
+public:
+    MergingDrawBatch(int batchId, mergeid_t mergeId) : DrawBatch(batchId, mergeId) {}
+
+    /*
+     * Checks if a (mergeable) op can be merged into this batch
+     *
+     * If true, the op's multiDraw must be guaranteed to handle both ops simultaneously, so it is
+     * important to consider all paint attributes used in the draw calls in deciding both a) if an
+     * op tries to merge at all, and b) if the op
+     *
+     * False positives can lead to information from the paints of subsequent merged operations being
+     * dropped, so we make simplifying qualifications on the ops that can merge, per op type.
+     */
+    bool canMergeWith(DrawOp* op) {
+        if (!op->state.mMatrix.isPureTranslate()) return false;
+
+        bool isTextBatch = getBatchId() == DeferredDisplayList::kOpBatch_Text ||
+                getBatchId() == DeferredDisplayList::kOpBatch_ColorText;
+
+        // Overlapping other operations is only allowed for text without shadow. For other ops,
+        // multiDraw isn't guaranteed to overdraw correctly
+        if (!isTextBatch || op->state.mDrawModifiers.mHasShadow) {
+            if (intersects(op->state.mBounds)) return false;
+        }
+
+        const DeferredDisplayState& lhs = op->state;
+        const DeferredDisplayState& rhs = mOps[0]->state;
+
+        if (NEQ_FALPHA(lhs.mAlpha, rhs.mAlpha)) return false;
+
+        // if paints are equal, then modifiers + paint attribs don't need to be compared
+        if (op->mPaint == mOps[0]->mPaint) return true;
+
+        if (op->getPaintAlpha() != mOps[0]->getPaintAlpha()) return false;
+
+        /* Draw Modifiers compatibility check
+         *
+         * Shadows are ignored, as only text uses them, and in that case they are drawn
+         * per-DrawTextOp, before the unified text draw. Because of this, it's always safe to merge
+         * text UNLESS a later draw's shadow should overlays a previous draw's text. This is covered
+         * above with the intersection check.
+         *
+         * OverrideLayerAlpha is also ignored, as it's only used for drawing layers, which are never
+         * merged.
+         *
+         * These ignore cases prevent us from simply memcmp'ing the drawModifiers
+         */
+
+        const DrawModifiers& lhsMod = lhs.mDrawModifiers;
+        const DrawModifiers& rhsMod = rhs.mDrawModifiers;
+        if (lhsMod.mShader != rhsMod.mShader) return false;
+        if (lhsMod.mColorFilter != rhsMod.mColorFilter) return false;
+
+        // Draw filter testing expects bit fields to be clear if filter not set.
+        if (lhsMod.mHasDrawFilter != rhsMod.mHasDrawFilter) return false;
+        if (lhsMod.mPaintFilterClearBits != rhsMod.mPaintFilterClearBits) return false;
+        if (lhsMod.mPaintFilterSetBits != rhsMod.mPaintFilterSetBits) return false;
+
+        return true;
+    }
+
+    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
+        DEFER_LOGD("%d  replaying DrawingBatch %p, with %d ops (batch id %x, merge id %p)",
+                index, this, mOps.size(), getBatchId(), getMergeId());
+        if (mOps.size() == 1) {
+            return DrawBatch::replay(renderer, dirty, false);
+        }
+
+        DrawOp* op = mOps[0];
+        status_t status = op->multiDraw(renderer, dirty, mOps, mBounds);
+        DisplayListLogBuffer& buffer = DisplayListLogBuffer::getInstance();
+        buffer.writeCommand(0, "multiDraw");
+        buffer.writeCommand(1, op->name());
+
+#if DEBUG_MERGE_BEHAVIOR
+        renderer.drawScreenSpaceColorRect(mBounds.left, mBounds.top, mBounds.right, mBounds.bottom,
+                DEBUG_COLOR_MERGEDBATCH);
+#endif
+        return status;
+    }
+};
+
+class StateOpBatch : public Batch {
 public:
     // creates a single operation batch
     StateOpBatch(StateOp* op) : mOp(op) {}
 
-    bool intersects(Rect& rect) {
-        // if something checks for intersection, it's trying to go backwards across a state op,
-        // something not currently supported - state ops are always barriers
-        CRASH();
-        return false;
-    }
-
-    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty) {
+    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
         DEFER_LOGD("replaying state op batch %p", this);
         renderer.restoreDisplayState(mOp->state);
 
@@ -124,18 +234,11 @@
     const StateOp* mOp;
 };
 
-class RestoreToCountBatch : public DrawOpBatch {
+class RestoreToCountBatch : public Batch {
 public:
     RestoreToCountBatch(StateOp* op, int restoreCount) : mOp(op), mRestoreCount(restoreCount) {}
 
-    bool intersects(Rect& rect) {
-        // if something checks for intersection, it's trying to go backwards across a state op,
-        // something not currently supported - state ops are always barriers
-        CRASH();
-        return false;
-    }
-
-    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty) {
+    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
         DEFER_LOGD("batch %p restoring to count %d", this, mRestoreCount);
 
         renderer.restoreDisplayState(mOp->state);
@@ -155,14 +258,30 @@
     const int mRestoreCount;
 };
 
+#if DEBUG_MERGE_BEHAVIOR
+class BarrierDebugBatch : public Batch {
+    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
+        renderer.drawScreenSpaceColorRect(0, 0, 10000, 10000, DEBUG_COLOR_BARRIER);
+        return DrawGlInfo::kStatusDrew;
+    }
+};
+#endif
+
 /////////////////////////////////////////////////////////////////////////////////
 // DeferredDisplayList
 /////////////////////////////////////////////////////////////////////////////////
 
 void DeferredDisplayList::resetBatchingState() {
     for (int i = 0; i < kOpBatch_Count; i++) {
-        mBatchIndices[i] = -1;
+        mBatchLookup[i] = NULL;
+        mMergingBatches[i].clear();
     }
+#if DEBUG_MERGE_BEHAVIOR
+    if (mBatches.size() != 0) {
+        mBatches.add(new BarrierDebugBatch());
+    }
+#endif
+    mEarliestBatchIndex = mBatches.size();
 }
 
 void DeferredDisplayList::clear() {
@@ -174,6 +293,7 @@
     }
     mBatches.clear();
     mSaveStack.clear();
+    mEarliestBatchIndex = 0;
 }
 
 /////////////////////////////////////////////////////////////////////////////////
@@ -282,28 +402,35 @@
         return; // quick rejected
     }
 
-    op->onDrawOpDeferred(renderer);
+    int batchId = kOpBatch_None;
+    mergeid_t mergeId = (mergeid_t) -1;
+    bool mergeable = op->onDefer(renderer, &batchId, &mergeId);
+
+    // complex clip has a complex set of expectations on the renderer state - for now, avoid taking
+    // the merge path in those cases
+    mergeable &= !recordingComplexClip();
 
     if (CC_UNLIKELY(renderer.getCaches().drawReorderDisabled)) {
         // TODO: elegant way to reuse batches?
-        DrawOpBatch* b = new DrawOpBatch();
+        DrawBatch* b = new DrawBatch(batchId, mergeId);
         b->add(op);
         mBatches.add(b);
         return;
     }
 
-    // disallowReorder isn't set, so find the latest batch of the new op's type, and try to merge
-    // the new op into it
-    DrawOpBatch* targetBatch = NULL;
-    int batchId = op->getBatchId();
+    // find the latest batch of the new op's type, and try to merge the new op into it
+    DrawBatch* targetBatch = NULL;
 
+    // insertion point of a new batch, will hopefully be immediately after similar batch
+    // (eventually, should be similar shader)
+    int insertBatchIndex = mBatches.size();
     if (!mBatches.isEmpty()) {
         if (op->state.mBounds.isEmpty()) {
             // don't know the bounds for op, so add to last batch and start from scratch on next op
-            mBatches.top()->add(op);
-            for (int i = 0; i < kOpBatch_Count; i++) {
-                mBatchIndices[i] = -1;
-            }
+            DrawBatch* b = new DrawBatch(batchId, mergeId);
+            b->add(op);
+            mBatches.add(b);
+            resetBatchingState();
 #if DEBUG_DEFER
             DEFER_LOGD("Warning: Encountered op with empty bounds, resetting batches");
             op->output(2);
@@ -311,13 +438,36 @@
             return;
         }
 
-        if (batchId >= 0 && mBatchIndices[batchId] != -1) {
-            int targetIndex = mBatchIndices[batchId];
-            targetBatch = mBatches[targetIndex];
+        if (mergeable) {
+            // Try to merge with any existing batch with same mergeId.
+            if (mMergingBatches[batchId].get(mergeId, targetBatch)) {
+                if (!((MergingDrawBatch*) targetBatch)->canMergeWith(op)) {
+                    targetBatch = NULL;
+                }
+            }
+        } else {
+            // join with similar, non-merging batch
+            targetBatch = (DrawBatch*)mBatchLookup[batchId];
+        }
+
+        if (targetBatch || mergeable) {
             // iterate back toward target to see if anything drawn since should overlap the new op
-            for (int i = mBatches.size() - 1; i > targetIndex; i--) {
-                DrawOpBatch* overBatch = mBatches[i];
+            // if no target, merging ops still interate to find similar batch to insert after
+            for (int i = mBatches.size() - 1; i >= mEarliestBatchIndex; i--) {
+                DrawBatch* overBatch = (DrawBatch*)mBatches[i];
+
+                if (overBatch == targetBatch) break;
+
+                // TODO: also consider shader shared between batch types
+                if (batchId == overBatch->getBatchId()) {
+                    insertBatchIndex = i + 1;
+                    if (!targetBatch) break; // found insert position, quit
+                }
+
                 if (overBatch->intersects(op->state.mBounds)) {
+                    // NOTE: it may be possible to optimize for special cases where two operations
+                    // of the same batch/paint could swap order, such as with a non-mergeable
+                    // (clipped) and a mergeable text operation
                     targetBatch = NULL;
 #if DEBUG_DEFER
                     DEFER_LOGD("op couldn't join batch %d, was intersected by batch %d",
@@ -329,13 +479,21 @@
             }
         }
     }
+
     if (!targetBatch) {
-        targetBatch = new DrawOpBatch();
-        mBatches.add(targetBatch);
-        if (batchId >= 0) {
-            mBatchIndices[batchId] = mBatches.size() - 1;
+        if (mergeable) {
+            targetBatch = new MergingDrawBatch(batchId, mergeId);
+            mMergingBatches[batchId].put(mergeId, targetBatch);
+        } else {
+            targetBatch = new DrawBatch(batchId, mergeId);
+            mBatchLookup[batchId] = targetBatch;
+            DEFER_LOGD("creating Batch %p, bid %x, at %d",
+                    targetBatch, batchId, insertBatchIndex);
         }
+
+        mBatches.insertAt(targetBatch, insertBatchIndex);
     }
+
     targetBatch->add(op);
 }
 
@@ -363,16 +521,14 @@
 // Replay / flush
 /////////////////////////////////////////////////////////////////////////////////
 
-static status_t replayBatchList(Vector<DrawOpBatch*>& batchList,
+static status_t replayBatchList(const Vector<Batch*>& batchList,
         OpenGLRenderer& renderer, Rect& dirty) {
     status_t status = DrawGlInfo::kStatusDone;
 
-    int opCount = 0;
     for (unsigned int i = 0; i < batchList.size(); i++) {
-        status |= batchList[i]->replay(renderer, dirty);
-        opCount += batchList[i]->count();
+        status |= batchList[i]->replay(renderer, dirty, i);
     }
-    DEFER_LOGD("--flushed, drew %d batches (total %d ops)", batchList.size(), opCount);
+    DEFER_LOGD("--flushed, drew %d batches", batchList.size());
     return status;
 }
 
@@ -400,7 +556,6 @@
     renderer.setDrawModifiers(restoreDrawModifiers);
 
     DEFER_LOGD("--flush complete, returning %x", status);
-
     clear();
     return status;
 }
diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h
index 653f315..9782c1c 100644
--- a/libs/hwui/DeferredDisplayList.h
+++ b/libs/hwui/DeferredDisplayList.h
@@ -22,6 +22,9 @@
 
 #include "Matrix.h"
 #include "Rect.h"
+#include "utils/TinyHashMap.h"
+
+class SkBitmap;
 
 namespace android {
 namespace uirenderer {
@@ -31,16 +34,21 @@
 class SaveOp;
 class SaveLayerOp;
 class StateOp;
-class DrawOpBatch;
 class OpenGLRenderer;
 
+class Batch;
+class DrawBatch;
+class MergingDrawBatch;
+
+typedef void* mergeid_t;
+
 class DeferredDisplayList {
 public:
     DeferredDisplayList() { clear(); }
     ~DeferredDisplayList() { clear(); }
 
     enum OpBatchId {
-        kOpBatch_None = -1, // Don't batch
+        kOpBatch_None = 0, // Don't batch
         kOpBatch_Bitmap,
         kOpBatch_Patch,
         kOpBatch_AlphaVertices,
@@ -96,8 +104,20 @@
     Vector<int> mSaveStack;
     int mComplexClipStackStart;
 
-    Vector<DrawOpBatch*> mBatches;
-    int mBatchIndices[kOpBatch_Count];
+    Vector<Batch*> mBatches;
+
+    // Maps batch ids to the most recent *non-merging* batch of that id
+    Batch* mBatchLookup[kOpBatch_Count];
+
+    // Points to the index after the most recent barrier
+    int mEarliestBatchIndex;
+
+    /**
+     * Maps the mergeid_t returned by an op's getMergeId() to the most recently seen
+     * MergingDrawBatch of that id. These ids are unique per draw type and guaranteed to not
+     * collide, which avoids the need to resolve mergeid collisions.
+     */
+    TinyHashMap<mergeid_t, DrawBatch*> mMergingBatches[kOpBatch_Count];
 };
 
 }; // namespace uirenderer
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index 36c95f9..26abec2 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -485,7 +485,7 @@
 
 #if DEBUG_DISPLAY_LIST
     Rect* clipRect = renderer.getClipRect();
-    DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.f, %.0f, %.0f",
+    DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.0f, %.0f, %.0f",
             level * 2, "", this, mName.string(), clipRect->left, clipRect->top,
             clipRect->right, clipRect->bottom);
 #endif
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index a5dee9f..ad7edb1 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -121,6 +121,7 @@
 };
 
 class DrawOp : public DisplayListOp {
+friend class MergingDrawBatch;
 public:
     DrawOp(SkPaint* paint)
             : mPaint(paint), mQuickRejected(false) {}
@@ -145,12 +146,41 @@
             return;
         }
 
-        replayStruct.mDrawGlStatus |= applyDraw(replayStruct.mRenderer, replayStruct.mDirty, level);
+        replayStruct.mDrawGlStatus |= applyDraw(replayStruct.mRenderer, replayStruct.mDirty);
     }
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) = 0;
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) = 0;
 
-    virtual void onDrawOpDeferred(OpenGLRenderer& renderer) {
+    /**
+     * Draw multiple instances of an operation, must be overidden for operations that merge
+     *
+     * Currently guarantees certain similarities between ops (see MergingDrawBatch::canMergeWith),
+     * and pure translation transformations. Other guarantees of similarity should be enforced by
+     * reducing which operations are tagged as mergeable.
+     */
+    virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
+            const Vector<DrawOp*>& ops, const Rect& bounds) {
+        status_t status = DrawGlInfo::kStatusDone;
+        for (unsigned int i = 0; i < ops.size(); i++) {
+            renderer.restoreDisplayState(ops[i]->state);
+            status |= ops[i]->applyDraw(renderer, dirty);
+        }
+        return status;
+    }
+
+    /*
+     * When this method is invoked the state field is initialized to have the
+     * final rendering state. We can thus use it to process data as it will be
+     * used at draw time.
+     *
+     * Additionally, this method allows subclasses to provide defer-time preferences for batching
+     * and merging.
+     *
+     * Return true if the op can merge with others of its kind (such subclasses should implement
+     * multiDraw)
+     */
+    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
+        return false;
     }
 
     // returns true if bounds exist
@@ -160,12 +190,11 @@
     void setQuickRejected(bool quickRejected) { mQuickRejected = quickRejected; }
     bool getQuickRejected() { return mQuickRejected; }
 
-    /** Batching disabled by default, turned on for individual ops */
-    virtual DeferredDisplayList::OpBatchId getBatchId() {
-        return DeferredDisplayList::kOpBatch_None;
+    inline int getPaintAlpha() {
+        return OpenGLRenderer::getAlphaDirect(mPaint);
     }
 
-    float strokeWidthOutset() {
+    inline float strokeWidthOutset() {
         float width = mPaint->getStrokeWidth();
         if (width == 0) return 0.5f; // account for hairline
         return width * 0.5f;
@@ -207,6 +236,14 @@
         return true;
     }
 
+    bool mergeAllowed() {
+        // checks that we're unclipped, and srcover
+        const Rect& opBounds = state.mBounds;
+        return fabs(opBounds.getWidth() - mLocalBounds.getWidth()) < 0.1 &&
+                fabs(opBounds.getHeight() - mLocalBounds.getHeight()) < 0.1 &&
+                (OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode);
+    }
+
 protected:
     Rect mLocalBounds; // displayed area in LOCAL coord. doesn't incorporate stroke, so check paint
 };
@@ -686,20 +723,58 @@
                     paint),
             mBitmap(bitmap) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
         return renderer.drawBitmap(mBitmap, mLocalBounds.left, mLocalBounds.top,
                 getPaint(renderer));
     }
 
+#define SET_TEXTURE(ptr, posRect, offsetRect, texCoordsRect, xDim, yDim) \
+    TextureVertex::set(ptr++, posRect.xDim - offsetRect.left, posRect.yDim - offsetRect.top, \
+            texCoordsRect.xDim, texCoordsRect.yDim)
+
+    virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
+            const Vector<DrawOp*>& ops, const Rect& bounds) {
+        renderer.restoreDisplayState(state, true); // restore all but the clip
+        renderer.setFullScreenClip(); // ensure merged ops aren't clipped
+        TextureVertex vertices[6 * ops.size()];
+        TextureVertex* vertex = &vertices[0];
+
+        // TODO: manually handle rect clip for bitmaps by adjusting texCoords per op, and allowing
+        // them to be merged in getBatchId()
+        const Rect texCoords(0, 0, 1, 1);
+
+        const float width = mBitmap->width();
+        const float height = mBitmap->height();
+        for (unsigned int i = 0; i < ops.size(); i++) {
+            const Rect& opBounds = ops[i]->state.mBounds;
+            SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, top);
+            SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, top);
+            SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, bottom);
+
+            SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, bottom);
+            SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, top);
+            SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, bottom);
+        }
+
+        return renderer.drawBitmaps(mBitmap, ops.size(), &vertices[0], bounds, mPaint);
+    }
+
     virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Draw bitmap %p at %f %f", mBitmap, mLocalBounds.left, mLocalBounds.top);
     }
 
     virtual const char* name() { return "DrawBitmap"; }
-    virtual DeferredDisplayList::OpBatchId getBatchId() {
-        return DeferredDisplayList::kOpBatch_Bitmap;
+
+    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
+        *batchId = DeferredDisplayList::kOpBatch_Bitmap;
+        *mergeId = (mergeid_t)mBitmap;
+
+        // don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in
+        // MergingDrawBatch::canMergeWith
+        return mergeAllowed() && (mBitmap->getConfig() != SkBitmap::kA8_Config);
     }
 
+    const SkBitmap* bitmap() { return mBitmap; }
 protected:
     SkBitmap* mBitmap;
 };
@@ -713,7 +788,7 @@
         transform.mapRect(mLocalBounds);
     }
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
         return renderer.drawBitmap(mBitmap, mMatrix, getPaint(renderer));
     }
 
@@ -721,9 +796,11 @@
         OP_LOG("Draw bitmap %p matrix " MATRIX_STRING, mBitmap, MATRIX_ARGS(mMatrix));
     }
 
-    virtual const char* name() { return "DrawBitmap"; }
-    virtual DeferredDisplayList::OpBatchId getBatchId() {
-        return DeferredDisplayList::kOpBatch_Bitmap;
+    virtual const char* name() { return "DrawBitmapMatrix"; }
+
+    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
+        *batchId = DeferredDisplayList::kOpBatch_Bitmap;
+        return false;
     }
 
 private:
@@ -738,7 +815,7 @@
             : DrawBoundedOp(dstLeft, dstTop, dstRight, dstBottom, paint),
             mBitmap(bitmap), mSrc(srcLeft, srcTop, srcRight, srcBottom) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
         return renderer.drawBitmap(mBitmap, mSrc.left, mSrc.top, mSrc.right, mSrc.bottom,
                 mLocalBounds.left, mLocalBounds.top, mLocalBounds.right, mLocalBounds.bottom,
                 getPaint(renderer));
@@ -750,8 +827,10 @@
     }
 
     virtual const char* name() { return "DrawBitmapRect"; }
-    virtual DeferredDisplayList::OpBatchId getBatchId() {
-        return DeferredDisplayList::kOpBatch_Bitmap;
+
+    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
+        *batchId = DeferredDisplayList::kOpBatch_Bitmap;
+        return false;
     }
 
 private:
@@ -764,7 +843,7 @@
     DrawBitmapDataOp(SkBitmap* bitmap, float left, float top, SkPaint* paint)
             : DrawBitmapOp(bitmap, left, top, paint) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
         return renderer.drawBitmapData(mBitmap, mLocalBounds.left,
                 mLocalBounds.top, getPaint(renderer));
     }
@@ -774,8 +853,10 @@
     }
 
     virtual const char* name() { return "DrawBitmapData"; }
-    virtual DeferredDisplayList::OpBatchId getBatchId() {
-        return DeferredDisplayList::kOpBatch_Bitmap;
+
+    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
+        *batchId = DeferredDisplayList::kOpBatch_Bitmap;
+        return false;
     }
 };
 
@@ -787,7 +868,7 @@
             mBitmap(bitmap), mMeshWidth(meshWidth), mMeshHeight(meshHeight),
             mVertices(vertices), mColors(colors) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
         return renderer.drawBitmapMesh(mBitmap, mMeshWidth, mMeshHeight,
                 mVertices, mColors, getPaint(renderer));
     }
@@ -797,8 +878,10 @@
     }
 
     virtual const char* name() { return "DrawBitmapMesh"; }
-    virtual DeferredDisplayList::OpBatchId getBatchId() {
-        return DeferredDisplayList::kOpBatch_Bitmap;
+
+    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
+        *batchId = DeferredDisplayList::kOpBatch_Bitmap;
+        return false;
     }
 
 private:
@@ -820,7 +903,7 @@
             mColors(colors), mxDivsCount(width), myDivsCount(height),
             mNumColors(numColors), mAlpha(alpha), mMode(mode) {};
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
         // NOTE: not calling the virtual method, which takes a paint
         return renderer.drawPatch(mBitmap, mxDivs, myDivs, mColors,
                 mxDivsCount, myDivsCount, mNumColors,
@@ -833,8 +916,11 @@
     }
 
     virtual const char* name() { return "DrawPatch"; }
-    virtual DeferredDisplayList::OpBatchId getBatchId() {
-        return DeferredDisplayList::kOpBatch_Patch;
+
+    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
+        *batchId = DeferredDisplayList::kOpBatch_Patch;
+        *mergeId = (mergeid_t)mBitmap;
+        return true;
     }
 
 private:
@@ -854,7 +940,7 @@
     DrawColorOp(int color, SkXfermode::Mode mode)
             : DrawOp(0), mColor(color), mMode(mode) {};
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
         return renderer.drawColor(mColor, mMode);
     }
 
@@ -882,13 +968,15 @@
         return true;
     }
 
-    virtual DeferredDisplayList::OpBatchId getBatchId() {
+    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
         if (mPaint->getPathEffect()) {
-            return DeferredDisplayList::kOpBatch_AlphaMaskTexture;
+            *batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture;
+        } else {
+            *batchId = mPaint->isAntiAlias() ?
+                    DeferredDisplayList::kOpBatch_AlphaVertices :
+                    DeferredDisplayList::kOpBatch_Vertices;
         }
-        return mPaint->isAntiAlias() ?
-                DeferredDisplayList::kOpBatch_AlphaVertices :
-                DeferredDisplayList::kOpBatch_Vertices;
+        return false;
     }
 };
 
@@ -897,7 +985,7 @@
     DrawRectOp(float left, float top, float right, float bottom, SkPaint* paint)
             : DrawStrokableOp(left, top, right, bottom, paint) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
         return renderer.drawRect(mLocalBounds.left, mLocalBounds.top,
                 mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
     }
@@ -915,7 +1003,7 @@
             : DrawBoundedOp(rects, count, paint),
             mRects(rects), mCount(count) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
         return renderer.drawRects(mRects, mCount, getPaint(renderer));
     }
 
@@ -925,8 +1013,9 @@
 
     virtual const char* name() { return "DrawRects"; }
 
-    virtual DeferredDisplayList::OpBatchId getBatchId() {
-        return DeferredDisplayList::kOpBatch_Vertices;
+    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
+        *batchId = DeferredDisplayList::kOpBatch_Vertices;
+        return false;
     }
 
 private:
@@ -940,7 +1029,7 @@
             float rx, float ry, SkPaint* paint)
             : DrawStrokableOp(left, top, right, bottom, paint), mRx(rx), mRy(ry) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
         return renderer.drawRoundRect(mLocalBounds.left, mLocalBounds.top,
                 mLocalBounds.right, mLocalBounds.bottom, mRx, mRy, getPaint(renderer));
     }
@@ -962,7 +1051,7 @@
             : DrawStrokableOp(x - radius, y - radius, x + radius, y + radius, paint),
             mX(x), mY(y), mRadius(radius) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
         return renderer.drawCircle(mX, mY, mRadius, getPaint(renderer));
     }
 
@@ -983,7 +1072,7 @@
     DrawOvalOp(float left, float top, float right, float bottom, SkPaint* paint)
             : DrawStrokableOp(left, top, right, bottom, paint) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
         return renderer.drawOval(mLocalBounds.left, mLocalBounds.top,
                 mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
     }
@@ -1002,7 +1091,7 @@
             : DrawStrokableOp(left, top, right, bottom, paint),
             mStartAngle(startAngle), mSweepAngle(sweepAngle), mUseCenter(useCenter) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
         return renderer.drawArc(mLocalBounds.left, mLocalBounds.top,
                 mLocalBounds.right, mLocalBounds.bottom,
                 mStartAngle, mSweepAngle, mUseCenter, getPaint(renderer));
@@ -1033,13 +1122,16 @@
         mLocalBounds.set(left, top, left + width, top + height);
     }
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
         return renderer.drawPath(mPath, getPaint(renderer));
     }
 
-    virtual void onDrawOpDeferred(OpenGLRenderer& renderer) {
+    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
         SkPaint* paint = getPaint(renderer);
         renderer.getCaches().pathCache.precache(mPath, paint);
+
+        *batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture;
+        return false;
     }
 
     virtual void output(int level, uint32_t logFlags) {
@@ -1048,9 +1140,6 @@
 
     virtual const char* name() { return "DrawPath"; }
 
-    virtual DeferredDisplayList::OpBatchId getBatchId() {
-        return DeferredDisplayList::kOpBatch_AlphaMaskTexture;
-    }
 private:
     SkPath* mPath;
 };
@@ -1063,7 +1152,7 @@
         mLocalBounds.outset(strokeWidthOutset());
     }
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
         return renderer.drawLines(mPoints, mCount, getPaint(renderer));
     }
 
@@ -1073,10 +1162,11 @@
 
     virtual const char* name() { return "DrawLines"; }
 
-    virtual DeferredDisplayList::OpBatchId getBatchId() {
-        return mPaint->isAntiAlias() ?
+    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
+        *batchId = mPaint->isAntiAlias() ?
                 DeferredDisplayList::kOpBatch_AlphaVertices :
                 DeferredDisplayList::kOpBatch_Vertices;
+        return false;
     }
 
 protected:
@@ -1089,7 +1179,7 @@
     DrawPointsOp(float* points, int count, SkPaint* paint)
             : DrawLinesOp(points, count, paint) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
         return renderer.drawPoints(mPoints, mCount, getPaint(renderer));
     }
 
@@ -1109,17 +1199,18 @@
         OP_LOG("Draw some text, %d bytes", mBytesCount);
     }
 
-    virtual void onDrawOpDeferred(OpenGLRenderer& renderer) {
+    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
         SkPaint* paint = getPaint(renderer);
         FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint);
         fontRenderer.precache(paint, mText, mCount, mat4::identity());
-    }
 
-    virtual DeferredDisplayList::OpBatchId getBatchId() {
-        return mPaint->getColor() == 0xff000000 ?
+        *batchId = mPaint->getColor() == 0xff000000 ?
                 DeferredDisplayList::kOpBatch_Text :
                 DeferredDisplayList::kOpBatch_ColorText;
+
+        return false;
     }
+
 protected:
     const char* mText;
     int mBytesCount;
@@ -1135,7 +1226,7 @@
         /* TODO: inherit from DrawBounded and init mLocalBounds */
     }
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
         return renderer.drawTextOnPath(mText, mBytesCount, mCount, mPath,
                 mHOffset, mVOffset, getPaint(renderer));
     }
@@ -1156,7 +1247,7 @@
         /* TODO: inherit from DrawBounded and init mLocalBounds */
     }
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
         return renderer.drawPosText(mText, mBytesCount, mCount, mPositions, getPaint(renderer));
     }
 
@@ -1189,12 +1280,7 @@
         memset(&mPrecacheTransform.data[0], 0xff, 16 * sizeof(float));
     }
 
-    /*
-     * When this method is invoked the state field  is initialized to have the
-     * final rendering state. We can thus use it to process data as it will be
-     * used at draw time.
-     */
-    virtual void onDrawOpDeferred(OpenGLRenderer& renderer) {
+    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
         SkPaint* paint = getPaint(renderer);
         FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint);
         const mat4& transform = renderer.findBestFontTransform(state.mMatrix);
@@ -1202,25 +1288,44 @@
             fontRenderer.precache(paint, mText, mCount, transform);
             mPrecacheTransform = transform;
         }
+        *batchId = mPaint->getColor() == 0xff000000 ?
+                DeferredDisplayList::kOpBatch_Text :
+                DeferredDisplayList::kOpBatch_ColorText;
+
+        *mergeId = (mergeid_t)mPaint->getColor();
+
+        // don't merge decorated text - the decorations won't draw in order
+        bool noDecorations = !(mPaint->getFlags() & (SkPaint::kUnderlineText_Flag |
+                        SkPaint::kStrikeThruText_Flag));
+        return mergeAllowed() && noDecorations;
     }
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
         return renderer.drawText(mText, mBytesCount, mCount, mX, mY,
                 mPositions, getPaint(renderer), mLength);
     }
 
+    virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
+            const Vector<DrawOp*>& ops, const Rect& bounds) {
+        status_t status = DrawGlInfo::kStatusDone;
+        renderer.setFullScreenClip(); // ensure merged ops aren't clipped
+        for (unsigned int i = 0; i < ops.size(); i++) {
+            DrawOpMode drawOpMode = (i == ops.size() - 1) ? kDrawOpMode_Flush : kDrawOpMode_Defer;
+            renderer.restoreDisplayState(ops[i]->state, true); // restore all but the clip
+
+            DrawTextOp& op = *((DrawTextOp*)ops[i]);
+            status |= renderer.drawText(op.mText, op.mBytesCount, op.mCount, op.mX, op.mY,
+                    op.mPositions, op.getPaint(renderer), op.mLength, drawOpMode);
+        }
+        return status;
+    }
+
     virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Draw Text of count %d, bytes %d", mCount, mBytesCount);
     }
 
     virtual const char* name() { return "DrawText"; }
 
-    virtual DeferredDisplayList::OpBatchId getBatchId() {
-        return mPaint->getColor() == 0xff000000 ?
-                DeferredDisplayList::kOpBatch_Text :
-                DeferredDisplayList::kOpBatch_ColorText;
-    }
-
 private:
     const char* mText;
     int mBytesCount;
@@ -1241,7 +1346,7 @@
     DrawFunctorOp(Functor* functor)
             : DrawOp(0), mFunctor(functor) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
         renderer.startMark("GL functor");
         status_t ret = renderer.callDrawGLFunction(mFunctor, dirty);
         renderer.endMark();
@@ -1269,14 +1374,14 @@
             mDisplayList->defer(deferStruct, level + 1);
         }
     }
-virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level) {
+    virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level) {
         if (mDisplayList && mDisplayList->isRenderable()) {
             mDisplayList->replay(replayStruct, level + 1);
         }
     }
 
     // NOT USED since replay() is overridden
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
         return DrawGlInfo::kStatusDone;
     }
 
@@ -1299,7 +1404,7 @@
     DrawLayerOp(Layer* layer, float x, float y)
             : DrawOp(0), mLayer(layer), mX(x), mY(y) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
         return renderer.drawLayer(mLayer, mX, mY);
     }
 
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 0b8f7e6..876c38a 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -276,6 +276,15 @@
     bitmap = refBitmap(bitmap);
     paint = refPaint(paint);
 
+    if (srcLeft == 0 && srcTop == 0 &&
+            srcRight == bitmap->width() && srcBottom == bitmap->height() &&
+            (srcBottom - srcTop == dstBottom - dstTop) &&
+            (srcRight - srcLeft == dstRight - dstLeft)) {
+        // transform simple rect to rect drawing case into position bitmap ops, since they merge
+        addDrawOp(new (alloc()) DrawBitmapOp(bitmap, dstLeft, dstTop, paint));
+        return DrawGlInfo::kStatusDone;
+    }
+
     addDrawOp(new (alloc()) DrawBitmapRectOp(bitmap,
                     srcLeft, srcTop, srcRight, srcBottom,
                     dstLeft, dstTop, dstRight, dstBottom, paint));
@@ -413,7 +422,9 @@
 }
 
 status_t DisplayListRenderer::drawText(const char* text, int bytesCount, int count,
-        float x, float y, const float* positions, SkPaint* paint, float length) {
+        float x, float y, const float* positions, SkPaint* paint,
+        float length, DrawOpMode drawOpMode) {
+
     if (!text || count <= 0) return DrawGlInfo::kStatusDone;
 
     if (length < 0.0f) length = paint->measureText(text, bytesCount);
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 19f7eb6..75abad6 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -121,8 +121,9 @@
             float hOffset, float vOffset, SkPaint* paint);
     virtual status_t drawPosText(const char* text, int bytesCount, int count,
             const float* positions, SkPaint* paint);
-    virtual status_t drawText(const char* text, int bytesCount, int count,
-            float x, float y, const float* positions, SkPaint* paint, float length);
+    virtual status_t drawText(const char* text, int bytesCount, int count, float x, float y,
+            const float* positions, SkPaint* paint, float length, DrawOpMode drawOpMode);
+
     virtual status_t drawRects(const float* rects, int count, SkPaint* paint);
 
     virtual void resetShader();
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 9612a4a..a9bf13e 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -59,7 +59,6 @@
 
     mGammaTable = NULL;
     mInitialized = false;
-    mMaxNumberOfQuads = 1024;
 
     mCurrentCacheTexture = NULL;
 
@@ -295,7 +294,7 @@
 }
 
 CacheTexture* FontRenderer::createCacheTexture(int width, int height, bool allocate) {
-    CacheTexture* cacheTexture = new CacheTexture(width, height, mMaxNumberOfQuads);
+    CacheTexture* cacheTexture = new CacheTexture(width, height, gMaxNumberOfQuads);
 
     if (allocate) {
         Caches::getInstance().activeTexture(0);
@@ -322,12 +321,12 @@
 
 // Avoid having to reallocate memory and render quad by quad
 void FontRenderer::initVertexArrayBuffers() {
-    uint32_t numIndices = mMaxNumberOfQuads * 6;
+    uint32_t numIndices = gMaxNumberOfQuads * 6;
     uint32_t indexBufferSizeBytes = numIndices * sizeof(uint16_t);
     uint16_t* indexBufferData = (uint16_t*) malloc(indexBufferSizeBytes);
 
     // Four verts, two triangles , six indices per quad
-    for (uint32_t i = 0; i < mMaxNumberOfQuads; i++) {
+    for (uint32_t i = 0; i < gMaxNumberOfQuads; i++) {
         int i6 = i * 6;
         int i4 = i * 4;
 
@@ -601,7 +600,7 @@
 
 bool FontRenderer::renderPosText(SkPaint* paint, const Rect* clip, const char *text,
         uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
-        const float* positions, Rect* bounds, Functor* functor) {
+        const float* positions, Rect* bounds, Functor* functor, bool forceFinish) {
     if (!mCurrentFont) {
         ALOGE("No font set");
         return false;
@@ -609,7 +608,10 @@
 
     initRender(clip, bounds, functor);
     mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y, positions);
-    finishRender();
+
+    if (forceFinish) {
+        finishRender();
+    }
 
     return mDrawn;
 }
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index f95ca1e..7e636e7 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -68,7 +68,8 @@
     // bounds is an out parameter
     bool renderPosText(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex,
             uint32_t len, int numGlyphs, int x, int y, const float* positions, Rect* bounds,
-            Functor* functor);
+            Functor* functor, bool forceFinish = true);
+
     // bounds is an out parameter
     bool renderTextOnPath(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex,
             uint32_t len, int numGlyphs, SkPath* path, float hOffset, float vOffset, Rect* bounds);
@@ -103,6 +104,8 @@
 private:
     friend class Font;
 
+    static const uint32_t gMaxNumberOfQuads = 2048;
+
     const uint8_t* mGammaTable;
 
     void allocateTextureMemory(CacheTexture* cacheTexture);
@@ -156,7 +159,6 @@
 
     bool mUploadTexture;
 
-    uint32_t mMaxNumberOfQuads;
     uint32_t mIndexBufferID;
 
     Functor* mFunctor;
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index a718294..4adad05 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -45,6 +45,7 @@
     fbo = 0;
     stencil = NULL;
     debugDrawUpdate = false;
+    hasDrawnSinceUpdate = false;
     deferredList = NULL;
     Caches::getInstance().resourceCache.incrementRefcount(this);
 }
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 715dfa4..7186603 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -317,6 +317,7 @@
     DisplayList* displayList;
     Rect dirtyRect;
     bool debugDrawUpdate;
+    bool hasDrawnSinceUpdate;
 
 private:
     /**
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index dcd1eb8..6fc2771 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -112,11 +112,9 @@
 
 OpenGLRenderer::OpenGLRenderer():
         mCaches(Caches::getInstance()), mExtensions(Extensions::getInstance()) {
-    mDrawModifiers.mShader = NULL;
-    mDrawModifiers.mColorFilter = NULL;
+    // *set* draw modifiers to be 0
+    memset(&mDrawModifiers, 0, sizeof(mDrawModifiers));
     mDrawModifiers.mOverrideLayerAlpha = 1.0f;
-    mDrawModifiers.mHasShadow = false;
-    mDrawModifiers.mHasDrawFilter = false;
 
     memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
 
@@ -552,6 +550,7 @@
         }
 
         layer->debugDrawUpdate = mCaches.debugLayersUpdates;
+        layer->hasDrawnSinceUpdate = false;
 
         return true;
     }
@@ -1090,11 +1089,28 @@
     }
 }
 
+/**
+ * Issues the command X, and if we're composing a save layer to the fbo or drawing a newly updated
+ * hardware layer with overdraw debug on, draws again to the stencil only, so that these draw
+ * operations are correctly counted twice for overdraw. NOTE: assumes composeLayerRegion only used
+ * by saveLayer's restore
+ */
+#define DRAW_DOUBLE_STENCIL_IF(COND, DRAW_COMMAND) {                             \
+        DRAW_COMMAND;                                                            \
+        if (CC_UNLIKELY(mCaches.debugOverdraw && getTargetFbo() == 0 && COND)) { \
+            glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);                 \
+            DRAW_COMMAND;                                                        \
+            glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);                     \
+        }                                                                        \
+    }
+
+#define DRAW_DOUBLE_STENCIL(DRAW_COMMAND) DRAW_DOUBLE_STENCIL_IF(true, DRAW_COMMAND)
+
 void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
     if (layer->region.isRect()) {
         layer->setRegionAsRect();
 
-        composeLayerRect(layer, layer->regionRect);
+        DRAW_DOUBLE_STENCIL(composeLayerRect(layer, layer->regionRect));
 
         layer->region.clear();
         return;
@@ -1164,14 +1180,16 @@
             numQuads++;
 
             if (numQuads >= REGION_MESH_QUAD_COUNT) {
-                glDrawElements(GL_TRIANGLES, numQuads * 6, GL_UNSIGNED_SHORT, NULL);
+                DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
+                                GL_UNSIGNED_SHORT, NULL));
                 numQuads = 0;
                 mesh = mCaches.getRegionMesh();
             }
         }
 
         if (numQuads > 0) {
-            glDrawElements(GL_TRIANGLES, numQuads * 6, GL_UNSIGNED_SHORT, NULL);
+            DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
+                            GL_UNSIGNED_SHORT, NULL));
         }
 
         finishDrawTexture();
@@ -1330,10 +1348,9 @@
         }
     }
 
-    if (stateDeferFlags & kStateDeferFlag_Clip) {
+    state.mClipValid = (stateDeferFlags & kStateDeferFlag_Clip);
+    if (state.mClipValid) {
         state.mClip.set(currentClip);
-    } else {
-        state.mClip.setEmpty();
     }
 
     // Transform, drawModifiers, and alpha always deferred, since they are used by state operations
@@ -1344,17 +1361,22 @@
     return false;
 }
 
-void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state) {
+void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore) {
     currentTransform().load(state.mMatrix);
     mDrawModifiers = state.mDrawModifiers;
     mSnapshot->alpha = state.mAlpha;
 
-    if (!state.mClip.isEmpty()) {
+    if (state.mClipValid && !skipClipRestore) {
         mSnapshot->setClip(state.mClip.left, state.mClip.top, state.mClip.right, state.mClip.bottom);
         dirtyClip();
     }
 }
 
+void OpenGLRenderer::setFullScreenClip() {
+    mSnapshot->setClip(0, 0, mWidth, mHeight);
+    dirtyClip();
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Transforms
 ///////////////////////////////////////////////////////////////////////////////
@@ -1963,6 +1985,42 @@
             (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
 }
 
+status_t OpenGLRenderer::drawBitmaps(SkBitmap* bitmap, int bitmapCount, TextureVertex* vertices,
+        const Rect& bounds, SkPaint* paint) {
+
+    // merged draw operations don't need scissor, but clip should still be valid
+    mCaches.setScissorEnabled(mScissorOptimizationDisabled);
+
+    mCaches.activeTexture(0);
+    Texture* texture = mCaches.textureCache.get(bitmap);
+    if (!texture) return DrawGlInfo::kStatusDone;
+    const AutoTexture autoCleanup(texture);
+
+    int alpha;
+    SkXfermode::Mode mode;
+    getAlphaAndMode(paint, &alpha, &mode);
+
+    texture->setWrap(GL_CLAMP_TO_EDGE, true);
+    texture->setFilter(GL_NEAREST, true); // merged ops are always pure-translation for now
+
+    const float x = (int) floorf(bounds.left + 0.5f);
+    const float y = (int) floorf(bounds.top + 0.5f);
+    if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) {
+        int color = paint != NULL ? paint->getColor() : 0;
+        drawAlpha8TextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
+                texture->id, paint != NULL, color, alpha, mode,
+                &vertices[0].position[0], &vertices[0].texture[0],
+                GL_TRIANGLES, bitmapCount * 6, true, true);
+    } else {
+        drawTextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
+                texture->id, alpha / 255.0f, mode, texture->blend,
+                &vertices[0].position[0], &vertices[0].texture[0],
+                GL_TRIANGLES, bitmapCount * 6, false, true, 0, true);
+    }
+
+    return DrawGlInfo::kStatusDrew;
+}
+
 status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint) {
     const float right = left + bitmap->width();
     const float bottom = top + bitmap->height();
@@ -2796,8 +2854,11 @@
 }
 
 status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
-        float x, float y, const float* positions, SkPaint* paint, float length) {
-    if (text == NULL || count == 0 || mSnapshot->isIgnored() || canSkipText(paint)) {
+        float x, float y, const float* positions, SkPaint* paint, float length,
+        DrawOpMode drawOpMode) {
+
+    if (drawOpMode == kDrawOpMode_Immediate &&
+            (text == NULL || count == 0 || mSnapshot->isIgnored() || canSkipText(paint))) {
         return DrawGlInfo::kStatusDone;
     }
 
@@ -2815,8 +2876,13 @@
 
     SkPaint::FontMetrics metrics;
     paint->getFontMetrics(&metrics, 0.0f);
-    if (quickReject(x, y + metrics.fTop, x + length, y + metrics.fBottom)) {
-        return DrawGlInfo::kStatusDone;
+    if (drawOpMode == kDrawOpMode_Immediate) {
+        if (quickReject(x, y + metrics.fTop, x + length, y + metrics.fBottom)) {
+            return DrawGlInfo::kStatusDone;
+        }
+    } else {
+        // merged draw operations don't need scissor, but clip should still be valid
+        mCaches.setScissorEnabled(mScissorOptimizationDisabled);
     }
 
     const float oldX = x;
@@ -2868,17 +2934,20 @@
 
     bool status;
     TextSetupFunctor functor(*this, x, y, pureTranslate, alpha, mode, paint);
+
+    // don't call issuedrawcommand, do it at end of batch
+    bool forceFinish = (drawOpMode != kDrawOpMode_Defer);
     if (CC_UNLIKELY(paint->getTextAlign() != SkPaint::kLeft_Align)) {
         SkPaint paintCopy(*paint);
         paintCopy.setTextAlign(SkPaint::kLeft_Align);
         status = fontRenderer.renderPosText(&paintCopy, clip, text, 0, bytesCount, count, x, y,
-                positions, hasActiveLayer ? &bounds : NULL, &functor);
+                positions, hasActiveLayer ? &bounds : NULL, &functor, forceFinish);
     } else {
         status = fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
-                positions, hasActiveLayer ? &bounds : NULL, &functor);
+                positions, hasActiveLayer ? &bounds : NULL, &functor, forceFinish);
     }
 
-    if (status && hasActiveLayer) {
+    if ((status || drawOpMode != kDrawOpMode_Immediate) && hasActiveLayer) {
         if (!pureTranslate) {
             transform.mapRect(bounds);
         }
@@ -2993,7 +3062,8 @@
         mDrawModifiers.mColorFilter = layer->getColorFilter();
 
         if (layer->region.isRect()) {
-            composeLayerRect(layer, layer->regionRect);
+            DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
+                    composeLayerRect(layer, layer->regionRect));
         } else if (layer->mesh) {
             const float a = getLayerAlpha(layer);
             setupDraw();
@@ -3019,8 +3089,9 @@
             }
             setupDrawMesh(&layer->mesh[0].position[0], &layer->mesh[0].texture[0]);
 
-            glDrawElements(GL_TRIANGLES, layer->meshElementCount,
-                    GL_UNSIGNED_SHORT, layer->meshIndices);
+            DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
+                    glDrawElements(GL_TRIANGLES, layer->meshElementCount,
+                            GL_UNSIGNED_SHORT, layer->meshIndices));
 
             finishDrawTexture();
 
@@ -3037,6 +3108,7 @@
                     0x7f00ff00, SkXfermode::kSrcOver_Mode);
         }
     }
+    layer->hasDrawnSinceUpdate = true;
 
     if (transform && !transform->isIdentity()) {
         restore();
@@ -3093,7 +3165,11 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void OpenGLRenderer::resetPaintFilter() {
+    // when clearing the PaintFilter, the masks should also be cleared for simple DrawModifier
+    // comparison, see MergingDrawBatch::canMergeWith
     mDrawModifiers.mHasDrawFilter = false;
+    mDrawModifiers.mPaintFilterClearBits = 0;
+    mDrawModifiers.mPaintFilterSetBits = 0;
 }
 
 void OpenGLRenderer::setupPaintFilter(int clearBits, int setBits) {
@@ -3365,7 +3441,7 @@
 void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, float bottom,
         GLuint texture, bool hasColor, int color, int alpha, SkXfermode::Mode mode,
         GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
-        bool ignoreTransform, bool dirty) {
+        bool ignoreTransform, bool ignoreScale, bool dirty) {
 
     setupDraw();
     setupDrawWithTexture(true);
@@ -3377,7 +3453,11 @@
     setupDrawBlending(true, mode);
     setupDrawProgram();
     if (!dirty) setupDrawDirtyRegionsDisabled();
-    setupDrawModelView(left, top, right, bottom, ignoreTransform);
+    if (!ignoreScale) {
+        setupDrawModelView(left, top, right, bottom, ignoreTransform);
+    } else {
+        setupDrawModelViewTranslate(left, top, right, bottom, ignoreTransform);
+    }
     setupDrawTexture(texture);
     setupDrawPureColorUniforms();
     setupDrawColorFilterUniforms();
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index dd7a5a2..a0ad888 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -71,10 +71,17 @@
     kStateDeferFlag_Clip = 0x2
 };
 
+enum DrawOpMode {
+    kDrawOpMode_Immediate,
+    kDrawOpMode_Defer,
+    kDrawOpMode_Flush
+};
+
 struct DeferredDisplayState {
-    Rect mBounds; // local bounds, mapped with matrix to be in screen space coordinates, clipped.
+    Rect mBounds; // global op bounds, mapped by mMatrix to be in screen space coordinates, clipped.
 
     // the below are set and used by the OpenGLRenderer at record and deferred playback
+    bool mClipValid;
     Rect mClip;
     mat4 mMatrix;
     DrawModifiers mDrawModifiers;
@@ -232,6 +239,8 @@
     virtual void outputDisplayList(DisplayList* displayList);
     virtual status_t drawLayer(Layer* layer, float x, float y);
     virtual status_t drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
+    status_t drawBitmaps(SkBitmap* bitmap, int bitmapCount, TextureVertex* vertices,
+            const Rect& bounds, SkPaint* paint);
     virtual status_t drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
     virtual status_t drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
             float srcRight, float srcBottom, float dstLeft, float dstTop,
@@ -261,7 +270,8 @@
     virtual status_t drawPosText(const char* text, int bytesCount, int count,
             const float* positions, SkPaint* paint);
     virtual status_t drawText(const char* text, int bytesCount, int count, float x, float y,
-            const float* positions, SkPaint* paint, float length = -1.0f);
+            const float* positions, SkPaint* paint, float length = -1.0f,
+            DrawOpMode drawOpMode = kDrawOpMode_Immediate);
     virtual status_t drawRects(const float* rects, int count, SkPaint* paint);
 
     virtual void resetShader();
@@ -282,7 +292,8 @@
     SkPaint* filterPaint(SkPaint* paint);
 
     bool storeDisplayState(DeferredDisplayState& state, int stateDeferFlags);
-    void restoreDisplayState(const DeferredDisplayState& state);
+    void restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore = false);
+    void setFullScreenClip();
 
     const DrawModifiers& getDrawModifiers() { return mDrawModifiers; }
     void setDrawModifiers(const DrawModifiers& drawModifiers) { mDrawModifiers = drawModifiers; }
@@ -336,20 +347,18 @@
      * @param mode Where to store the resulting xfermode
      */
     static inline void getAlphaAndModeDirect(SkPaint* paint, int* alpha, SkXfermode::Mode* mode) {
-        if (paint) {
-            *mode = getXfermode(paint->getXfermode());
+        *mode = getXfermodeDirect(paint);
+        *alpha = getAlphaDirect(paint);
+    }
 
-            // Skia draws using the color's alpha channel if < 255
-            // Otherwise, it uses the paint's alpha
-            int color = paint->getColor();
-            *alpha = (color >> 24) & 0xFF;
-            if (*alpha == 255) {
-                *alpha = paint->getAlpha();
-            }
-        } else {
-            *mode = SkXfermode::kSrcOver_Mode;
-            *alpha = 255;
-        }
+    static inline SkXfermode::Mode getXfermodeDirect(SkPaint* paint) {
+        if (!paint) return SkXfermode::kSrcOver_Mode;
+        return getXfermode(paint->getXfermode());
+    }
+
+    static inline int getAlphaDirect(SkPaint* paint) {
+        if (!paint) return 255;
+        return paint->getAlpha();
     }
 
     /**
@@ -358,6 +367,20 @@
      */
     mat4 findBestFontTransform(const mat4& transform) const;
 
+#if DEBUG_MERGE_BEHAVIOR
+    void drawScreenSpaceColorRect(float left, float top, float right, float bottom, int color) {
+        mCaches.setScissorEnabled(false);
+
+        // should only be called outside of other draw ops, so stencil can only be in test state
+        bool stencilWasEnabled = mCaches.stencil.isTestEnabled();
+        mCaches.stencil.disable();
+
+        drawColorRect(left, top, right, bottom, color, SkXfermode::kSrcOver_Mode, true);
+
+        if (stencilWasEnabled) mCaches.stencil.enableTest();
+    }
+#endif
+
 protected:
     /**
      * Computes the projection matrix, initialize the first snapshot
@@ -778,7 +801,7 @@
     void drawAlpha8TextureMesh(float left, float top, float right, float bottom,
             GLuint texture, bool hasColor, int color, int alpha, SkXfermode::Mode mode,
             GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
-            bool ignoreTransform, bool dirty = true);
+            bool ignoreTransform, bool ignoreScale = false, bool dirty = true);
 
     /**
      * Draws text underline and strike-through if needed.
diff --git a/libs/hwui/utils/TinyHashMap.h b/libs/hwui/utils/TinyHashMap.h
new file mode 100644
index 0000000..8855140
--- /dev/null
+++ b/libs/hwui/utils/TinyHashMap.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2013 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_HWUI_TINYHASHMAP_H
+#define ANDROID_HWUI_TINYHASHMAP_H
+
+#include <utils/BasicHashtable.h>
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * A very simple hash map that doesn't allow duplicate keys, overwriting the older entry.
+ *
+ * Currently, expects simple keys that are handled by hash_t()
+ */
+template <typename TKey, typename TValue>
+class TinyHashMap {
+public:
+    typedef key_value_pair_t<TKey, TValue> TEntry;
+
+    /**
+     * Puts an entry in the hash, removing any existing entry with the same key
+     */
+    void put(TKey key, TValue value) {
+        hash_t hash = hash_t(key);
+
+        ssize_t index = mTable.find(-1, hash, key);
+        if (index != -1) {
+            mTable.removeAt(index);
+        }
+
+        TEntry initEntry(key, value);
+        mTable.add(hash, initEntry);
+    }
+
+    /**
+     * Return true if key is in the map, in which case stores the value in the output ref
+     */
+    bool get(TKey key, TValue& outValue) {
+        hash_t hash = hash_t(key);
+        ssize_t index = mTable.find(-1, hash, key);
+        if (index == -1) {
+            return false;
+        }
+        outValue = mTable.entryAt(index).value;
+        return true;
+    }
+
+    void clear() { mTable.clear(); }
+
+private:
+    BasicHashtable<TKey, TEntry> mTable;
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_TINYHASHMAP_H
diff --git a/opengl/java/android/opengl/GLES20.java b/opengl/java/android/opengl/GLES20.java
index dd9f8b8..8261474 100644
--- a/opengl/java/android/opengl/GLES20.java
+++ b/opengl/java/android/opengl/GLES20.java
@@ -296,6 +296,10 @@
     public static final int GL_RGB5_A1                                 = 0x8057;
     public static final int GL_RGB565                                  = 0x8D62;
     public static final int GL_DEPTH_COMPONENT16                       = 0x81A5;
+    // GL_STENCIL_INDEX does not appear in gl2.h or gl2ext.h, and there is no
+    // token with value 0x1901.
+    //
+    @Deprecated
     public static final int GL_STENCIL_INDEX                           = 0x1901;
     public static final int GL_STENCIL_INDEX8                          = 0x8D48;
     public static final int GL_RENDERBUFFER_WIDTH                      = 0x8D42;
@@ -327,7 +331,7 @@
 
     native private static void _nativeClassInit();
     static {
-	    _nativeClassInit();
+        _nativeClassInit();
     }
     // C function void glActiveTexture ( GLenum texture )
 
@@ -1025,7 +1029,7 @@
     );
 
     // C function void glGetProgramInfoLog( GLuint program, GLsizei maxLength, GLsizei * length,
- 	//     GLchar * infoLog);
+    //     GLchar * infoLog);
 
     public static native String glGetProgramInfoLog(
         int program
@@ -1065,7 +1069,7 @@
     );
 
     // C function void glGetShaderInfoLog( GLuint shader, GLsizei maxLength, GLsizei * length,
- 	//     GLchar * infoLog);
+    //     GLchar * infoLog);
 
     public static native String glGetShaderInfoLog(
         int shader
diff --git a/opengl/java/android/opengl/GLES30.java b/opengl/java/android/opengl/GLES30.java
new file mode 100644
index 0000000..9164849
--- /dev/null
+++ b/opengl/java/android/opengl/GLES30.java
@@ -0,0 +1,1794 @@
+/*
+**
+** Copyright 2013, 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.
+*/
+
+// This source file is automatically generated
+
+package android.opengl;
+
+/** OpenGL ES 3.0
+ */
+public class GLES30 extends GLES20 {
+    public static final int GL_READ_BUFFER                             = 0x0C02;
+    public static final int GL_UNPACK_ROW_LENGTH                       = 0x0CF2;
+    public static final int GL_UNPACK_SKIP_ROWS                        = 0x0CF3;
+    public static final int GL_UNPACK_SKIP_PIXELS                      = 0x0CF4;
+    public static final int GL_PACK_ROW_LENGTH                         = 0x0D02;
+    public static final int GL_PACK_SKIP_ROWS                          = 0x0D03;
+    public static final int GL_PACK_SKIP_PIXELS                        = 0x0D04;
+    public static final int GL_COLOR                                   = 0x1800;
+    public static final int GL_DEPTH                                   = 0x1801;
+    public static final int GL_STENCIL                                 = 0x1802;
+    public static final int GL_RED                                     = 0x1903;
+    public static final int GL_RGB8                                    = 0x8051;
+    public static final int GL_RGBA8                                   = 0x8058;
+    public static final int GL_RGB10_A2                                = 0x8059;
+    public static final int GL_TEXTURE_BINDING_3D                      = 0x806A;
+    public static final int GL_UNPACK_SKIP_IMAGES                      = 0x806D;
+    public static final int GL_UNPACK_IMAGE_HEIGHT                     = 0x806E;
+    public static final int GL_TEXTURE_3D                              = 0x806F;
+    public static final int GL_TEXTURE_WRAP_R                          = 0x8072;
+    public static final int GL_MAX_3D_TEXTURE_SIZE                     = 0x8073;
+    public static final int GL_UNSIGNED_INT_2_10_10_10_REV             = 0x8368;
+    public static final int GL_MAX_ELEMENTS_VERTICES                   = 0x80E8;
+    public static final int GL_MAX_ELEMENTS_INDICES                    = 0x80E9;
+    public static final int GL_TEXTURE_MIN_LOD                         = 0x813A;
+    public static final int GL_TEXTURE_MAX_LOD                         = 0x813B;
+    public static final int GL_TEXTURE_BASE_LEVEL                      = 0x813C;
+    public static final int GL_TEXTURE_MAX_LEVEL                       = 0x813D;
+    public static final int GL_MIN                                     = 0x8007;
+    public static final int GL_MAX                                     = 0x8008;
+    public static final int GL_DEPTH_COMPONENT24                       = 0x81A6;
+    public static final int GL_MAX_TEXTURE_LOD_BIAS                    = 0x84FD;
+    public static final int GL_TEXTURE_COMPARE_MODE                    = 0x884C;
+    public static final int GL_TEXTURE_COMPARE_FUNC                    = 0x884D;
+    public static final int GL_CURRENT_QUERY                           = 0x8865;
+    public static final int GL_QUERY_RESULT                            = 0x8866;
+    public static final int GL_QUERY_RESULT_AVAILABLE                  = 0x8867;
+    public static final int GL_BUFFER_MAPPED                           = 0x88BC;
+    public static final int GL_BUFFER_MAP_POINTER                      = 0x88BD;
+    public static final int GL_STREAM_READ                             = 0x88E1;
+    public static final int GL_STREAM_COPY                             = 0x88E2;
+    public static final int GL_STATIC_READ                             = 0x88E5;
+    public static final int GL_STATIC_COPY                             = 0x88E6;
+    public static final int GL_DYNAMIC_READ                            = 0x88E9;
+    public static final int GL_DYNAMIC_COPY                            = 0x88EA;
+    public static final int GL_MAX_DRAW_BUFFERS                        = 0x8824;
+    public static final int GL_DRAW_BUFFER0                            = 0x8825;
+    public static final int GL_DRAW_BUFFER1                            = 0x8826;
+    public static final int GL_DRAW_BUFFER2                            = 0x8827;
+    public static final int GL_DRAW_BUFFER3                            = 0x8828;
+    public static final int GL_DRAW_BUFFER4                            = 0x8829;
+    public static final int GL_DRAW_BUFFER5                            = 0x882A;
+    public static final int GL_DRAW_BUFFER6                            = 0x882B;
+    public static final int GL_DRAW_BUFFER7                            = 0x882C;
+    public static final int GL_DRAW_BUFFER8                            = 0x882D;
+    public static final int GL_DRAW_BUFFER9                            = 0x882E;
+    public static final int GL_DRAW_BUFFER10                           = 0x882F;
+    public static final int GL_DRAW_BUFFER11                           = 0x8830;
+    public static final int GL_DRAW_BUFFER12                           = 0x8831;
+    public static final int GL_DRAW_BUFFER13                           = 0x8832;
+    public static final int GL_DRAW_BUFFER14                           = 0x8833;
+    public static final int GL_DRAW_BUFFER15                           = 0x8834;
+    public static final int GL_MAX_FRAGMENT_UNIFORM_COMPONENTS         = 0x8B49;
+    public static final int GL_MAX_VERTEX_UNIFORM_COMPONENTS           = 0x8B4A;
+    public static final int GL_SAMPLER_3D                              = 0x8B5F;
+    public static final int GL_SAMPLER_2D_SHADOW                       = 0x8B62;
+    public static final int GL_FRAGMENT_SHADER_DERIVATIVE_HINT         = 0x8B8B;
+    public static final int GL_PIXEL_PACK_BUFFER                       = 0x88EB;
+    public static final int GL_PIXEL_UNPACK_BUFFER                     = 0x88EC;
+    public static final int GL_PIXEL_PACK_BUFFER_BINDING               = 0x88ED;
+    public static final int GL_PIXEL_UNPACK_BUFFER_BINDING             = 0x88EF;
+    public static final int GL_FLOAT_MAT2x3                            = 0x8B65;
+    public static final int GL_FLOAT_MAT2x4                            = 0x8B66;
+    public static final int GL_FLOAT_MAT3x2                            = 0x8B67;
+    public static final int GL_FLOAT_MAT3x4                            = 0x8B68;
+    public static final int GL_FLOAT_MAT4x2                            = 0x8B69;
+    public static final int GL_FLOAT_MAT4x3                            = 0x8B6A;
+    public static final int GL_SRGB                                    = 0x8C40;
+    public static final int GL_SRGB8                                   = 0x8C41;
+    public static final int GL_SRGB8_ALPHA8                            = 0x8C43;
+    public static final int GL_COMPARE_REF_TO_TEXTURE                  = 0x884E;
+    public static final int GL_MAJOR_VERSION                           = 0x821B;
+    public static final int GL_MINOR_VERSION                           = 0x821C;
+    public static final int GL_NUM_EXTENSIONS                          = 0x821D;
+    public static final int GL_RGBA32F                                 = 0x8814;
+    public static final int GL_RGB32F                                  = 0x8815;
+    public static final int GL_RGBA16F                                 = 0x881A;
+    public static final int GL_RGB16F                                  = 0x881B;
+    public static final int GL_VERTEX_ATTRIB_ARRAY_INTEGER             = 0x88FD;
+    public static final int GL_MAX_ARRAY_TEXTURE_LAYERS                = 0x88FF;
+    public static final int GL_MIN_PROGRAM_TEXEL_OFFSET                = 0x8904;
+    public static final int GL_MAX_PROGRAM_TEXEL_OFFSET                = 0x8905;
+    public static final int GL_MAX_VARYING_COMPONENTS                  = 0x8B4B;
+    public static final int GL_TEXTURE_2D_ARRAY                        = 0x8C1A;
+    public static final int GL_TEXTURE_BINDING_2D_ARRAY                = 0x8C1D;
+    public static final int GL_R11F_G11F_B10F                          = 0x8C3A;
+    public static final int GL_UNSIGNED_INT_10F_11F_11F_REV            = 0x8C3B;
+    public static final int GL_RGB9_E5                                 = 0x8C3D;
+    public static final int GL_UNSIGNED_INT_5_9_9_9_REV                = 0x8C3E;
+    public static final int GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH   = 0x8C76;
+    public static final int GL_TRANSFORM_FEEDBACK_BUFFER_MODE          = 0x8C7F;
+    public static final int GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS   = 0x8C80;
+    public static final int GL_TRANSFORM_FEEDBACK_VARYINGS             = 0x8C83;
+    public static final int GL_TRANSFORM_FEEDBACK_BUFFER_START         = 0x8C84;
+    public static final int GL_TRANSFORM_FEEDBACK_BUFFER_SIZE          = 0x8C85;
+    public static final int GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN   = 0x8C88;
+    public static final int GL_RASTERIZER_DISCARD                      = 0x8C89;
+    public static final int GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS    = 0x8C8A;
+    public static final int GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS = 0x8C8B;
+    public static final int GL_INTERLEAVED_ATTRIBS                     = 0x8C8C;
+    public static final int GL_SEPARATE_ATTRIBS                        = 0x8C8D;
+    public static final int GL_TRANSFORM_FEEDBACK_BUFFER               = 0x8C8E;
+    public static final int GL_TRANSFORM_FEEDBACK_BUFFER_BINDING       = 0x8C8F;
+    public static final int GL_RGBA32UI                                = 0x8D70;
+    public static final int GL_RGB32UI                                 = 0x8D71;
+    public static final int GL_RGBA16UI                                = 0x8D76;
+    public static final int GL_RGB16UI                                 = 0x8D77;
+    public static final int GL_RGBA8UI                                 = 0x8D7C;
+    public static final int GL_RGB8UI                                  = 0x8D7D;
+    public static final int GL_RGBA32I                                 = 0x8D82;
+    public static final int GL_RGB32I                                  = 0x8D83;
+    public static final int GL_RGBA16I                                 = 0x8D88;
+    public static final int GL_RGB16I                                  = 0x8D89;
+    public static final int GL_RGBA8I                                  = 0x8D8E;
+    public static final int GL_RGB8I                                   = 0x8D8F;
+    public static final int GL_RED_INTEGER                             = 0x8D94;
+    public static final int GL_RGB_INTEGER                             = 0x8D98;
+    public static final int GL_RGBA_INTEGER                            = 0x8D99;
+    public static final int GL_SAMPLER_2D_ARRAY                        = 0x8DC1;
+    public static final int GL_SAMPLER_2D_ARRAY_SHADOW                 = 0x8DC4;
+    public static final int GL_SAMPLER_CUBE_SHADOW                     = 0x8DC5;
+    public static final int GL_UNSIGNED_INT_VEC2                       = 0x8DC6;
+    public static final int GL_UNSIGNED_INT_VEC3                       = 0x8DC7;
+    public static final int GL_UNSIGNED_INT_VEC4                       = 0x8DC8;
+    public static final int GL_INT_SAMPLER_2D                          = 0x8DCA;
+    public static final int GL_INT_SAMPLER_3D                          = 0x8DCB;
+    public static final int GL_INT_SAMPLER_CUBE                        = 0x8DCC;
+    public static final int GL_INT_SAMPLER_2D_ARRAY                    = 0x8DCF;
+    public static final int GL_UNSIGNED_INT_SAMPLER_2D                 = 0x8DD2;
+    public static final int GL_UNSIGNED_INT_SAMPLER_3D                 = 0x8DD3;
+    public static final int GL_UNSIGNED_INT_SAMPLER_CUBE               = 0x8DD4;
+    public static final int GL_UNSIGNED_INT_SAMPLER_2D_ARRAY           = 0x8DD7;
+    public static final int GL_BUFFER_ACCESS_FLAGS                     = 0x911F;
+    public static final int GL_BUFFER_MAP_LENGTH                       = 0x9120;
+    public static final int GL_BUFFER_MAP_OFFSET                       = 0x9121;
+    public static final int GL_DEPTH_COMPONENT32F                      = 0x8CAC;
+    public static final int GL_DEPTH32F_STENCIL8                       = 0x8CAD;
+    public static final int GL_FLOAT_32_UNSIGNED_INT_24_8_REV          = 0x8DAD;
+    public static final int GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING   = 0x8210;
+    public static final int GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE   = 0x8211;
+    public static final int GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE         = 0x8212;
+    public static final int GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE       = 0x8213;
+    public static final int GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE        = 0x8214;
+    public static final int GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE       = 0x8215;
+    public static final int GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE       = 0x8216;
+    public static final int GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE     = 0x8217;
+    public static final int GL_FRAMEBUFFER_DEFAULT                     = 0x8218;
+    public static final int GL_FRAMEBUFFER_UNDEFINED                   = 0x8219;
+    public static final int GL_DEPTH_STENCIL_ATTACHMENT                = 0x821A;
+    public static final int GL_DEPTH_STENCIL                           = 0x84F9;
+    public static final int GL_UNSIGNED_INT_24_8                       = 0x84FA;
+    public static final int GL_DEPTH24_STENCIL8                        = 0x88F0;
+    public static final int GL_UNSIGNED_NORMALIZED                     = 0x8C17;
+    public static final int GL_DRAW_FRAMEBUFFER_BINDING                = GL_FRAMEBUFFER_BINDING;
+    public static final int GL_READ_FRAMEBUFFER                        = 0x8CA8;
+    public static final int GL_DRAW_FRAMEBUFFER                        = 0x8CA9;
+    public static final int GL_READ_FRAMEBUFFER_BINDING                = 0x8CAA;
+    public static final int GL_RENDERBUFFER_SAMPLES                    = 0x8CAB;
+    public static final int GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER    = 0x8CD4;
+    public static final int GL_MAX_COLOR_ATTACHMENTS                   = 0x8CDF;
+    public static final int GL_COLOR_ATTACHMENT1                       = 0x8CE1;
+    public static final int GL_COLOR_ATTACHMENT2                       = 0x8CE2;
+    public static final int GL_COLOR_ATTACHMENT3                       = 0x8CE3;
+    public static final int GL_COLOR_ATTACHMENT4                       = 0x8CE4;
+    public static final int GL_COLOR_ATTACHMENT5                       = 0x8CE5;
+    public static final int GL_COLOR_ATTACHMENT6                       = 0x8CE6;
+    public static final int GL_COLOR_ATTACHMENT7                       = 0x8CE7;
+    public static final int GL_COLOR_ATTACHMENT8                       = 0x8CE8;
+    public static final int GL_COLOR_ATTACHMENT9                       = 0x8CE9;
+    public static final int GL_COLOR_ATTACHMENT10                      = 0x8CEA;
+    public static final int GL_COLOR_ATTACHMENT11                      = 0x8CEB;
+    public static final int GL_COLOR_ATTACHMENT12                      = 0x8CEC;
+    public static final int GL_COLOR_ATTACHMENT13                      = 0x8CED;
+    public static final int GL_COLOR_ATTACHMENT14                      = 0x8CEE;
+    public static final int GL_COLOR_ATTACHMENT15                      = 0x8CEF;
+    public static final int GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE      = 0x8D56;
+    public static final int GL_MAX_SAMPLES                             = 0x8D57;
+    public static final int GL_HALF_FLOAT                              = 0x140B;
+    public static final int GL_MAP_READ_BIT                            = 0x0001;
+    public static final int GL_MAP_WRITE_BIT                           = 0x0002;
+    public static final int GL_MAP_INVALIDATE_RANGE_BIT                = 0x0004;
+    public static final int GL_MAP_INVALIDATE_BUFFER_BIT               = 0x0008;
+    public static final int GL_MAP_FLUSH_EXPLICIT_BIT                  = 0x0010;
+    public static final int GL_MAP_UNSYNCHRONIZED_BIT                  = 0x0020;
+    public static final int GL_RG                                      = 0x8227;
+    public static final int GL_RG_INTEGER                              = 0x8228;
+    public static final int GL_R8                                      = 0x8229;
+    public static final int GL_RG8                                     = 0x822B;
+    public static final int GL_R16F                                    = 0x822D;
+    public static final int GL_R32F                                    = 0x822E;
+    public static final int GL_RG16F                                   = 0x822F;
+    public static final int GL_RG32F                                   = 0x8230;
+    public static final int GL_R8I                                     = 0x8231;
+    public static final int GL_R8UI                                    = 0x8232;
+    public static final int GL_R16I                                    = 0x8233;
+    public static final int GL_R16UI                                   = 0x8234;
+    public static final int GL_R32I                                    = 0x8235;
+    public static final int GL_R32UI                                   = 0x8236;
+    public static final int GL_RG8I                                    = 0x8237;
+    public static final int GL_RG8UI                                   = 0x8238;
+    public static final int GL_RG16I                                   = 0x8239;
+    public static final int GL_RG16UI                                  = 0x823A;
+    public static final int GL_RG32I                                   = 0x823B;
+    public static final int GL_RG32UI                                  = 0x823C;
+    public static final int GL_VERTEX_ARRAY_BINDING                    = 0x85B5;
+    public static final int GL_R8_SNORM                                = 0x8F94;
+    public static final int GL_RG8_SNORM                               = 0x8F95;
+    public static final int GL_RGB8_SNORM                              = 0x8F96;
+    public static final int GL_RGBA8_SNORM                             = 0x8F97;
+    public static final int GL_SIGNED_NORMALIZED                       = 0x8F9C;
+    public static final int GL_PRIMITIVE_RESTART_FIXED_INDEX           = 0x8D69;
+    public static final int GL_COPY_READ_BUFFER                        = 0x8F36;
+    public static final int GL_COPY_WRITE_BUFFER                       = 0x8F37;
+    public static final int GL_COPY_READ_BUFFER_BINDING                = GL_COPY_READ_BUFFER;
+    public static final int GL_COPY_WRITE_BUFFER_BINDING               = GL_COPY_WRITE_BUFFER;
+    public static final int GL_UNIFORM_BUFFER                          = 0x8A11;
+    public static final int GL_UNIFORM_BUFFER_BINDING                  = 0x8A28;
+    public static final int GL_UNIFORM_BUFFER_START                    = 0x8A29;
+    public static final int GL_UNIFORM_BUFFER_SIZE                     = 0x8A2A;
+    public static final int GL_MAX_VERTEX_UNIFORM_BLOCKS               = 0x8A2B;
+    public static final int GL_MAX_FRAGMENT_UNIFORM_BLOCKS             = 0x8A2D;
+    public static final int GL_MAX_COMBINED_UNIFORM_BLOCKS             = 0x8A2E;
+    public static final int GL_MAX_UNIFORM_BUFFER_BINDINGS             = 0x8A2F;
+    public static final int GL_MAX_UNIFORM_BLOCK_SIZE                  = 0x8A30;
+    public static final int GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS  = 0x8A31;
+    public static final int GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS     = 0x8A33;
+    public static final int GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT         = 0x8A34;
+    public static final int GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH    = 0x8A35;
+    public static final int GL_ACTIVE_UNIFORM_BLOCKS                   = 0x8A36;
+    public static final int GL_UNIFORM_TYPE                            = 0x8A37;
+    public static final int GL_UNIFORM_SIZE                            = 0x8A38;
+    public static final int GL_UNIFORM_NAME_LENGTH                     = 0x8A39;
+    public static final int GL_UNIFORM_BLOCK_INDEX                     = 0x8A3A;
+    public static final int GL_UNIFORM_OFFSET                          = 0x8A3B;
+    public static final int GL_UNIFORM_ARRAY_STRIDE                    = 0x8A3C;
+    public static final int GL_UNIFORM_MATRIX_STRIDE                   = 0x8A3D;
+    public static final int GL_UNIFORM_IS_ROW_MAJOR                    = 0x8A3E;
+    public static final int GL_UNIFORM_BLOCK_BINDING                   = 0x8A3F;
+    public static final int GL_UNIFORM_BLOCK_DATA_SIZE                 = 0x8A40;
+    public static final int GL_UNIFORM_BLOCK_NAME_LENGTH               = 0x8A41;
+    public static final int GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS           = 0x8A42;
+    public static final int GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES    = 0x8A43;
+    public static final int GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER    = 0x8A44;
+    public static final int GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER  = 0x8A46;
+    // GL_INVALID_INDEX is defined as 0xFFFFFFFFu in C.
+    public static final int GL_INVALID_INDEX                           = -1;
+    public static final int GL_MAX_VERTEX_OUTPUT_COMPONENTS            = 0x9122;
+    public static final int GL_MAX_FRAGMENT_INPUT_COMPONENTS           = 0x9125;
+    public static final int GL_MAX_SERVER_WAIT_TIMEOUT                 = 0x9111;
+    public static final int GL_OBJECT_TYPE                             = 0x9112;
+    public static final int GL_SYNC_CONDITION                          = 0x9113;
+    public static final int GL_SYNC_STATUS                             = 0x9114;
+    public static final int GL_SYNC_FLAGS                              = 0x9115;
+    public static final int GL_SYNC_FENCE                              = 0x9116;
+    public static final int GL_SYNC_GPU_COMMANDS_COMPLETE              = 0x9117;
+    public static final int GL_UNSIGNALED                              = 0x9118;
+    public static final int GL_SIGNALED                                = 0x9119;
+    public static final int GL_ALREADY_SIGNALED                        = 0x911A;
+    public static final int GL_TIMEOUT_EXPIRED                         = 0x911B;
+    public static final int GL_CONDITION_SATISFIED                     = 0x911C;
+    public static final int GL_WAIT_FAILED                             = 0x911D;
+    public static final int GL_SYNC_FLUSH_COMMANDS_BIT                 = 0x00000001;
+    // GL_TIMEOUT_IGNORED is defined as 0xFFFFFFFFFFFFFFFFull in C.
+    public static final long GL_TIMEOUT_IGNORED                         = -1;
+    public static final int GL_VERTEX_ATTRIB_ARRAY_DIVISOR             = 0x88FE;
+    public static final int GL_ANY_SAMPLES_PASSED                      = 0x8C2F;
+    public static final int GL_ANY_SAMPLES_PASSED_CONSERVATIVE         = 0x8D6A;
+    public static final int GL_SAMPLER_BINDING                         = 0x8919;
+    public static final int GL_RGB10_A2UI                              = 0x906F;
+    public static final int GL_TEXTURE_SWIZZLE_R                       = 0x8E42;
+    public static final int GL_TEXTURE_SWIZZLE_G                       = 0x8E43;
+    public static final int GL_TEXTURE_SWIZZLE_B                       = 0x8E44;
+    public static final int GL_TEXTURE_SWIZZLE_A                       = 0x8E45;
+    public static final int GL_GREEN                                   = 0x1904;
+    public static final int GL_BLUE                                    = 0x1905;
+    public static final int GL_INT_2_10_10_10_REV                      = 0x8D9F;
+    public static final int GL_TRANSFORM_FEEDBACK                      = 0x8E22;
+    public static final int GL_TRANSFORM_FEEDBACK_PAUSED               = 0x8E23;
+    public static final int GL_TRANSFORM_FEEDBACK_ACTIVE               = 0x8E24;
+    public static final int GL_TRANSFORM_FEEDBACK_BINDING              = 0x8E25;
+    public static final int GL_PROGRAM_BINARY_RETRIEVABLE_HINT         = 0x8257;
+    public static final int GL_PROGRAM_BINARY_LENGTH                   = 0x8741;
+    public static final int GL_NUM_PROGRAM_BINARY_FORMATS              = 0x87FE;
+    public static final int GL_PROGRAM_BINARY_FORMATS                  = 0x87FF;
+    public static final int GL_COMPRESSED_R11_EAC                      = 0x9270;
+    public static final int GL_COMPRESSED_SIGNED_R11_EAC               = 0x9271;
+    public static final int GL_COMPRESSED_RG11_EAC                     = 0x9272;
+    public static final int GL_COMPRESSED_SIGNED_RG11_EAC              = 0x9273;
+    public static final int GL_COMPRESSED_RGB8_ETC2                    = 0x9274;
+    public static final int GL_COMPRESSED_SRGB8_ETC2                   = 0x9275;
+    public static final int GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2     = 0x9276;
+    public static final int GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2    = 0x9277;
+    public static final int GL_COMPRESSED_RGBA8_ETC2_EAC               = 0x9278;
+    public static final int GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC        = 0x9279;
+    public static final int GL_TEXTURE_IMMUTABLE_FORMAT                = 0x912F;
+    public static final int GL_MAX_ELEMENT_INDEX                       = 0x8D6B;
+    public static final int GL_NUM_SAMPLE_COUNTS                       = 0x9380;
+    public static final int GL_TEXTURE_IMMUTABLE_LEVELS                = 0x82DF;
+
+    native private static void _nativeClassInit();
+    static {
+        _nativeClassInit();
+    }
+
+    // C function void glReadBuffer ( GLenum mode )
+
+    public static native void glReadBuffer(
+        int mode
+    );
+
+    // C function void glDrawRangeElements ( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices )
+
+    public static native void glDrawRangeElements(
+        int mode,
+        int start,
+        int end,
+        int count,
+        int type,
+        java.nio.Buffer indices
+    );
+
+    // C function void glDrawRangeElements ( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, GLsizei offset )
+
+    public static native void glDrawRangeElements(
+        int mode,
+        int start,
+        int end,
+        int count,
+        int type,
+        int offset
+    );
+
+    // C function void glTexImage3D ( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels )
+
+    public static native void glTexImage3D(
+        int target,
+        int level,
+        int internalformat,
+        int width,
+        int height,
+        int depth,
+        int border,
+        int format,
+        int type,
+        java.nio.Buffer pixels
+    );
+
+    // C function void glTexImage3D ( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, GLsizei offset )
+
+    public static native void glTexImage3D(
+        int target,
+        int level,
+        int internalformat,
+        int width,
+        int height,
+        int depth,
+        int border,
+        int format,
+        int type,
+        int offset
+    );
+
+    // C function void glTexSubImage3D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels )
+
+    public static native void glTexSubImage3D(
+        int target,
+        int level,
+        int xoffset,
+        int yoffset,
+        int zoffset,
+        int width,
+        int height,
+        int depth,
+        int format,
+        int type,
+        java.nio.Buffer pixels
+    );
+
+    // C function void glTexSubImage3D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei offset )
+
+    public static native void glTexSubImage3D(
+        int target,
+        int level,
+        int xoffset,
+        int yoffset,
+        int zoffset,
+        int width,
+        int height,
+        int depth,
+        int format,
+        int type,
+        int offset
+    );
+
+    // C function void glCopyTexSubImage3D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height )
+
+    public static native void glCopyTexSubImage3D(
+        int target,
+        int level,
+        int xoffset,
+        int yoffset,
+        int zoffset,
+        int x,
+        int y,
+        int width,
+        int height
+    );
+
+    // C function void glCompressedTexImage3D ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data )
+
+    public static native void glCompressedTexImage3D(
+        int target,
+        int level,
+        int internalformat,
+        int width,
+        int height,
+        int depth,
+        int border,
+        int imageSize,
+        java.nio.Buffer data
+    );
+
+    // C function void glCompressedTexImage3D ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, GLsizei offset )
+
+    public static native void glCompressedTexImage3D(
+        int target,
+        int level,
+        int internalformat,
+        int width,
+        int height,
+        int depth,
+        int border,
+        int imageSize,
+        int offset
+    );
+
+    // C function void glCompressedTexSubImage3D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data )
+
+    public static native void glCompressedTexSubImage3D(
+        int target,
+        int level,
+        int xoffset,
+        int yoffset,
+        int zoffset,
+        int width,
+        int height,
+        int depth,
+        int format,
+        int imageSize,
+        java.nio.Buffer data
+    );
+
+    // C function void glCompressedTexSubImage3D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, GLsizei offset )
+
+    public static native void glCompressedTexSubImage3D(
+        int target,
+        int level,
+        int xoffset,
+        int yoffset,
+        int zoffset,
+        int width,
+        int height,
+        int depth,
+        int format,
+        int imageSize,
+        int offset
+    );
+
+    // C function void glGenQueries ( GLsizei n, GLuint *ids )
+
+    public static native void glGenQueries(
+        int n,
+        int[] ids,
+        int offset
+    );
+
+    // C function void glGenQueries ( GLsizei n, GLuint *ids )
+
+    public static native void glGenQueries(
+        int n,
+        java.nio.IntBuffer ids
+    );
+
+    // C function void glDeleteQueries ( GLsizei n, const GLuint *ids )
+
+    public static native void glDeleteQueries(
+        int n,
+        int[] ids,
+        int offset
+    );
+
+    // C function void glDeleteQueries ( GLsizei n, const GLuint *ids )
+
+    public static native void glDeleteQueries(
+        int n,
+        java.nio.IntBuffer ids
+    );
+
+    // C function GLboolean glIsQuery ( GLuint id )
+
+    public static native boolean glIsQuery(
+        int id
+    );
+
+    // C function void glBeginQuery ( GLenum target, GLuint id )
+
+    public static native void glBeginQuery(
+        int target,
+        int id
+    );
+
+    // C function void glEndQuery ( GLenum target )
+
+    public static native void glEndQuery(
+        int target
+    );
+
+    // C function void glGetQueryiv ( GLenum target, GLenum pname, GLint *params )
+
+    public static native void glGetQueryiv(
+        int target,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    // C function void glGetQueryiv ( GLenum target, GLenum pname, GLint *params )
+
+    public static native void glGetQueryiv(
+        int target,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    // C function void glGetQueryObjectuiv ( GLuint id, GLenum pname, GLuint *params )
+
+    public static native void glGetQueryObjectuiv(
+        int id,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    // C function void glGetQueryObjectuiv ( GLuint id, GLenum pname, GLuint *params )
+
+    public static native void glGetQueryObjectuiv(
+        int id,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    // C function GLboolean glUnmapBuffer ( GLenum target )
+
+    public static native boolean glUnmapBuffer(
+        int target
+    );
+
+    // C function void glGetBufferPointerv ( GLenum target, GLenum pname, GLvoid** params )
+
+    public static native java.nio.Buffer glGetBufferPointerv(
+        int target,
+        int pname
+    );
+
+    // C function void glDrawBuffers ( GLsizei n, const GLenum *bufs )
+
+    public static native void glDrawBuffers(
+        int n,
+        int[] bufs,
+        int offset
+    );
+
+    // C function void glDrawBuffers ( GLsizei n, const GLenum *bufs )
+
+    public static native void glDrawBuffers(
+        int n,
+        java.nio.IntBuffer bufs
+    );
+
+    // C function void glUniformMatrix2x3fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value )
+
+    public static native void glUniformMatrix2x3fv(
+        int location,
+        int count,
+        boolean transpose,
+        float[] value,
+        int offset
+    );
+
+    // C function void glUniformMatrix2x3fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value )
+
+    public static native void glUniformMatrix2x3fv(
+        int location,
+        int count,
+        boolean transpose,
+        java.nio.FloatBuffer value
+    );
+
+    // C function void glUniformMatrix3x2fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value )
+
+    public static native void glUniformMatrix3x2fv(
+        int location,
+        int count,
+        boolean transpose,
+        float[] value,
+        int offset
+    );
+
+    // C function void glUniformMatrix3x2fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value )
+
+    public static native void glUniformMatrix3x2fv(
+        int location,
+        int count,
+        boolean transpose,
+        java.nio.FloatBuffer value
+    );
+
+    // C function void glUniformMatrix2x4fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value )
+
+    public static native void glUniformMatrix2x4fv(
+        int location,
+        int count,
+        boolean transpose,
+        float[] value,
+        int offset
+    );
+
+    // C function void glUniformMatrix2x4fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value )
+
+    public static native void glUniformMatrix2x4fv(
+        int location,
+        int count,
+        boolean transpose,
+        java.nio.FloatBuffer value
+    );
+
+    // C function void glUniformMatrix4x2fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value )
+
+    public static native void glUniformMatrix4x2fv(
+        int location,
+        int count,
+        boolean transpose,
+        float[] value,
+        int offset
+    );
+
+    // C function void glUniformMatrix4x2fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value )
+
+    public static native void glUniformMatrix4x2fv(
+        int location,
+        int count,
+        boolean transpose,
+        java.nio.FloatBuffer value
+    );
+
+    // C function void glUniformMatrix3x4fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value )
+
+    public static native void glUniformMatrix3x4fv(
+        int location,
+        int count,
+        boolean transpose,
+        float[] value,
+        int offset
+    );
+
+    // C function void glUniformMatrix3x4fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value )
+
+    public static native void glUniformMatrix3x4fv(
+        int location,
+        int count,
+        boolean transpose,
+        java.nio.FloatBuffer value
+    );
+
+    // C function void glUniformMatrix4x3fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value )
+
+    public static native void glUniformMatrix4x3fv(
+        int location,
+        int count,
+        boolean transpose,
+        float[] value,
+        int offset
+    );
+
+    // C function void glUniformMatrix4x3fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value )
+
+    public static native void glUniformMatrix4x3fv(
+        int location,
+        int count,
+        boolean transpose,
+        java.nio.FloatBuffer value
+    );
+
+    // C function void glBlitFramebuffer ( GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter )
+
+    public static native void glBlitFramebuffer(
+        int srcX0,
+        int srcY0,
+        int srcX1,
+        int srcY1,
+        int dstX0,
+        int dstY0,
+        int dstX1,
+        int dstY1,
+        int mask,
+        int filter
+    );
+
+    // C function void glRenderbufferStorageMultisample ( GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height )
+
+    public static native void glRenderbufferStorageMultisample(
+        int target,
+        int samples,
+        int internalformat,
+        int width,
+        int height
+    );
+
+    // C function void glFramebufferTextureLayer ( GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer )
+
+    public static native void glFramebufferTextureLayer(
+        int target,
+        int attachment,
+        int texture,
+        int level,
+        int layer
+    );
+
+    // C function GLvoid * glMapBufferRange ( GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access )
+
+    public static native java.nio.Buffer glMapBufferRange(
+        int target,
+        int offset,
+        int length,
+        int access
+    );
+
+    // C function void glFlushMappedBufferRange ( GLenum target, GLintptr offset, GLsizeiptr length )
+
+    public static native void glFlushMappedBufferRange(
+        int target,
+        int offset,
+        int length
+    );
+
+    // C function void glBindVertexArray ( GLuint array )
+
+    public static native void glBindVertexArray(
+        int array
+    );
+
+    // C function void glDeleteVertexArrays ( GLsizei n, const GLuint *arrays )
+
+    public static native void glDeleteVertexArrays(
+        int n,
+        int[] arrays,
+        int offset
+    );
+
+    // C function void glDeleteVertexArrays ( GLsizei n, const GLuint *arrays )
+
+    public static native void glDeleteVertexArrays(
+        int n,
+        java.nio.IntBuffer arrays
+    );
+
+    // C function void glGenVertexArrays ( GLsizei n, GLuint *arrays )
+
+    public static native void glGenVertexArrays(
+        int n,
+        int[] arrays,
+        int offset
+    );
+
+    // C function void glGenVertexArrays ( GLsizei n, GLuint *arrays )
+
+    public static native void glGenVertexArrays(
+        int n,
+        java.nio.IntBuffer arrays
+    );
+
+    // C function GLboolean glIsVertexArray ( GLuint array )
+
+    public static native boolean glIsVertexArray(
+        int array
+    );
+
+    // C function void glGetIntegeri_v ( GLenum target, GLuint index, GLint *data )
+
+    public static native void glGetIntegeri_v(
+        int target,
+        int index,
+        int[] data,
+        int offset
+    );
+
+    // C function void glGetIntegeri_v ( GLenum target, GLuint index, GLint *data )
+
+    public static native void glGetIntegeri_v(
+        int target,
+        int index,
+        java.nio.IntBuffer data
+    );
+
+    // C function void glBeginTransformFeedback ( GLenum primitiveMode )
+
+    public static native void glBeginTransformFeedback(
+        int primitiveMode
+    );
+
+    // C function void glEndTransformFeedback ( void )
+
+    public static native void glEndTransformFeedback(
+    );
+
+    // C function void glBindBufferRange ( GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size )
+
+    public static native void glBindBufferRange(
+        int target,
+        int index,
+        int buffer,
+        int offset,
+        int size
+    );
+
+    // C function void glBindBufferBase ( GLenum target, GLuint index, GLuint buffer )
+
+    public static native void glBindBufferBase(
+        int target,
+        int index,
+        int buffer
+    );
+
+	// C function void glTransformFeedbackVaryings ( GLuint program, GLsizei count, const GLchar *varyings, GLenum bufferMode )
+
+	public static native void glTransformFeedbackVaryings(
+        int program,
+        String[] varyings,
+        int bufferMode
+	);
+
+    // C function void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name )
+
+    public static native void glGetTransformFeedbackVarying(
+        int program,
+        int index,
+        int bufsize,
+        int[] length,
+        int lengthOffset,
+        int[] size,
+        int sizeOffset,
+        int[] type,
+        int typeOffset,
+        byte[] name,
+        int nameOffset
+    );
+
+    // C function void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name )
+
+    public static native void glGetTransformFeedbackVarying(
+        int program,
+        int index,
+        int bufsize,
+        java.nio.IntBuffer length,
+        java.nio.IntBuffer size,
+        java.nio.IntBuffer type,
+        byte name
+    );
+
+    // C function void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name )
+
+    public static native String glGetTransformFeedbackVarying(
+        int program,
+        int index,
+        int[] size,
+        int sizeOffset,
+        int[] type,
+        int typeOffset
+    );
+
+    // C function void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name )
+
+    public static native String glGetTransformFeedbackVarying(
+        int program,
+        int index,
+        java.nio.IntBuffer size,
+        java.nio.IntBuffer type
+    );
+
+    // C function void glVertexAttribIPointer ( GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer )
+
+    private static native void glVertexAttribIPointerBounds(
+        int index,
+        int size,
+        int type,
+        int stride,
+        java.nio.Buffer pointer,
+        int remaining
+    );
+
+    public static void glVertexAttribIPointer(
+        int index,
+        int size,
+        int type,
+        int stride,
+        java.nio.Buffer pointer
+    ) {
+        glVertexAttribIPointerBounds(
+            index,
+            size,
+            type,
+            stride,
+            pointer,
+            pointer.remaining()
+        );
+    }
+
+    // C function void glVertexAttribIPointer ( GLuint index, GLint size, GLenum type, GLsizei stride, GLsizei offset )
+
+    public static native void glVertexAttribIPointer(
+        int index,
+        int size,
+        int type,
+        int stride,
+        int offset
+    );
+
+    // C function void glGetVertexAttribIiv ( GLuint index, GLenum pname, GLint *params )
+
+    public static native void glGetVertexAttribIiv(
+        int index,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    // C function void glGetVertexAttribIiv ( GLuint index, GLenum pname, GLint *params )
+
+    public static native void glGetVertexAttribIiv(
+        int index,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    // C function void glGetVertexAttribIuiv ( GLuint index, GLenum pname, GLuint *params )
+
+    public static native void glGetVertexAttribIuiv(
+        int index,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    // C function void glGetVertexAttribIuiv ( GLuint index, GLenum pname, GLuint *params )
+
+    public static native void glGetVertexAttribIuiv(
+        int index,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    // C function void glVertexAttribI4i ( GLuint index, GLint x, GLint y, GLint z, GLint w )
+
+    public static native void glVertexAttribI4i(
+        int index,
+        int x,
+        int y,
+        int z,
+        int w
+    );
+
+    // C function void glVertexAttribI4ui ( GLuint index, GLuint x, GLuint y, GLuint z, GLuint w )
+
+    public static native void glVertexAttribI4ui(
+        int index,
+        int x,
+        int y,
+        int z,
+        int w
+    );
+
+    // C function void glVertexAttribI4iv ( GLuint index, const GLint *v )
+
+    public static native void glVertexAttribI4iv(
+        int index,
+        int[] v,
+        int offset
+    );
+
+    // C function void glVertexAttribI4iv ( GLuint index, const GLint *v )
+
+    public static native void glVertexAttribI4iv(
+        int index,
+        java.nio.IntBuffer v
+    );
+
+    // C function void glVertexAttribI4uiv ( GLuint index, const GLuint *v )
+
+    public static native void glVertexAttribI4uiv(
+        int index,
+        int[] v,
+        int offset
+    );
+
+    // C function void glVertexAttribI4uiv ( GLuint index, const GLuint *v )
+
+    public static native void glVertexAttribI4uiv(
+        int index,
+        java.nio.IntBuffer v
+    );
+
+    // C function void glGetUniformuiv ( GLuint program, GLint location, GLuint *params )
+
+    public static native void glGetUniformuiv(
+        int program,
+        int location,
+        int[] params,
+        int offset
+    );
+
+    // C function void glGetUniformuiv ( GLuint program, GLint location, GLuint *params )
+
+    public static native void glGetUniformuiv(
+        int program,
+        int location,
+        java.nio.IntBuffer params
+    );
+
+    // C function GLint glGetFragDataLocation ( GLuint program, const GLchar *name )
+
+    public static native int glGetFragDataLocation(
+        int program,
+        String name
+    );
+
+    // C function void glUniform1ui ( GLint location, GLuint v0 )
+
+    public static native void glUniform1ui(
+        int location,
+        int v0
+    );
+
+    // C function void glUniform2ui ( GLint location, GLuint v0, GLuint v1 )
+
+    public static native void glUniform2ui(
+        int location,
+        int v0,
+        int v1
+    );
+
+    // C function void glUniform3ui ( GLint location, GLuint v0, GLuint v1, GLuint v2 )
+
+    public static native void glUniform3ui(
+        int location,
+        int v0,
+        int v1,
+        int v2
+    );
+
+    // C function void glUniform4ui ( GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3 )
+
+    public static native void glUniform4ui(
+        int location,
+        int v0,
+        int v1,
+        int v2,
+        int v3
+    );
+
+    // C function void glUniform1uiv ( GLint location, GLsizei count, const GLuint *value )
+
+    public static native void glUniform1uiv(
+        int location,
+        int count,
+        int[] value,
+        int offset
+    );
+
+    // C function void glUniform1uiv ( GLint location, GLsizei count, const GLuint *value )
+
+    public static native void glUniform1uiv(
+        int location,
+        int count,
+        java.nio.IntBuffer value
+    );
+
+    // C function void glUniform2uiv ( GLint location, GLsizei count, const GLuint *value )
+
+    public static native void glUniform2uiv(
+        int location,
+        int count,
+        int[] value,
+        int offset
+    );
+
+    // C function void glUniform2uiv ( GLint location, GLsizei count, const GLuint *value )
+
+    public static native void glUniform2uiv(
+        int location,
+        int count,
+        java.nio.IntBuffer value
+    );
+
+    // C function void glUniform3uiv ( GLint location, GLsizei count, const GLuint *value )
+
+    public static native void glUniform3uiv(
+        int location,
+        int count,
+        int[] value,
+        int offset
+    );
+
+    // C function void glUniform3uiv ( GLint location, GLsizei count, const GLuint *value )
+
+    public static native void glUniform3uiv(
+        int location,
+        int count,
+        java.nio.IntBuffer value
+    );
+
+    // C function void glUniform4uiv ( GLint location, GLsizei count, const GLuint *value )
+
+    public static native void glUniform4uiv(
+        int location,
+        int count,
+        int[] value,
+        int offset
+    );
+
+    // C function void glUniform4uiv ( GLint location, GLsizei count, const GLuint *value )
+
+    public static native void glUniform4uiv(
+        int location,
+        int count,
+        java.nio.IntBuffer value
+    );
+
+    // C function void glClearBufferiv ( GLenum buffer, GLint drawbuffer, const GLint *value )
+
+    public static native void glClearBufferiv(
+        int buffer,
+        int drawbuffer,
+        int[] value,
+        int offset
+    );
+
+    // C function void glClearBufferiv ( GLenum buffer, GLint drawbuffer, const GLint *value )
+
+    public static native void glClearBufferiv(
+        int buffer,
+        int drawbuffer,
+        java.nio.IntBuffer value
+    );
+
+    // C function void glClearBufferuiv ( GLenum buffer, GLint drawbuffer, const GLuint *value )
+
+    public static native void glClearBufferuiv(
+        int buffer,
+        int drawbuffer,
+        int[] value,
+        int offset
+    );
+
+    // C function void glClearBufferuiv ( GLenum buffer, GLint drawbuffer, const GLuint *value )
+
+    public static native void glClearBufferuiv(
+        int buffer,
+        int drawbuffer,
+        java.nio.IntBuffer value
+    );
+
+    // C function void glClearBufferfv ( GLenum buffer, GLint drawbuffer, const GLfloat *value )
+
+    public static native void glClearBufferfv(
+        int buffer,
+        int drawbuffer,
+        float[] value,
+        int offset
+    );
+
+    // C function void glClearBufferfv ( GLenum buffer, GLint drawbuffer, const GLfloat *value )
+
+    public static native void glClearBufferfv(
+        int buffer,
+        int drawbuffer,
+        java.nio.FloatBuffer value
+    );
+
+    // C function void glClearBufferfi ( GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil )
+
+    public static native void glClearBufferfi(
+        int buffer,
+        int drawbuffer,
+        float depth,
+        int stencil
+    );
+
+    // C function const GLubyte * glGetStringi ( GLenum name, GLuint index )
+
+    public static native String glGetStringi(
+        int name,
+        int index
+    );
+
+    // C function void glCopyBufferSubData ( GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size )
+
+    public static native void glCopyBufferSubData(
+        int readTarget,
+        int writeTarget,
+        int readOffset,
+        int writeOffset,
+        int size
+    );
+
+	// C function void glGetUniformIndices ( GLuint program, GLsizei uniformCount, const GLchar *const *uniformNames, GLuint *uniformIndices )
+
+	public static native void glGetUniformIndices(
+        int program,
+        String[] uniformNames,
+        int[] uniformIndices,
+        int uniformIndicesOffset
+	);
+
+    // C function void glGetUniformIndices ( GLuint program, GLsizei uniformCount, const GLchar *const *uniformNames, GLuint *uniformIndices )
+
+    public static native void glGetUniformIndices(
+        int program,
+        String[] uniformNames,
+        java.nio.IntBuffer uniformIndices
+    );
+
+    // C function void glGetActiveUniformsiv ( GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params )
+
+    public static native void glGetActiveUniformsiv(
+        int program,
+        int uniformCount,
+        int[] uniformIndices,
+        int uniformIndicesOffset,
+        int pname,
+        int[] params,
+        int paramsOffset
+    );
+
+    // C function void glGetActiveUniformsiv ( GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params )
+
+    public static native void glGetActiveUniformsiv(
+        int program,
+        int uniformCount,
+        java.nio.IntBuffer uniformIndices,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    // C function GLuint glGetUniformBlockIndex ( GLuint program, const GLchar *uniformBlockName )
+
+    public static native int glGetUniformBlockIndex(
+        int program,
+        String uniformBlockName
+    );
+
+    // C function void glGetActiveUniformBlockiv ( GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params )
+
+    public static native void glGetActiveUniformBlockiv(
+        int program,
+        int uniformBlockIndex,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    // C function void glGetActiveUniformBlockiv ( GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params )
+
+    public static native void glGetActiveUniformBlockiv(
+        int program,
+        int uniformBlockIndex,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    // C function void glGetActiveUniformBlockName ( GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName )
+
+    public static native void glGetActiveUniformBlockName(
+        int program,
+        int uniformBlockIndex,
+        int bufSize,
+        int[] length,
+        int lengthOffset,
+        byte[] uniformBlockName,
+        int uniformBlockNameOffset
+    );
+
+    // C function void glGetActiveUniformBlockName ( GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName )
+
+    public static native void glGetActiveUniformBlockName(
+        int program,
+        int uniformBlockIndex,
+        java.nio.Buffer length,
+        java.nio.Buffer uniformBlockName
+    );
+
+    // C function void glGetActiveUniformBlockName ( GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName )
+
+    public static native String glGetActiveUniformBlockName(
+        int program,
+        int uniformBlockIndex
+    );
+
+    // C function void glUniformBlockBinding ( GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding )
+
+    public static native void glUniformBlockBinding(
+        int program,
+        int uniformBlockIndex,
+        int uniformBlockBinding
+    );
+
+    // C function void glDrawArraysInstanced ( GLenum mode, GLint first, GLsizei count, GLsizei instanceCount )
+
+    public static native void glDrawArraysInstanced(
+        int mode,
+        int first,
+        int count,
+        int instanceCount
+    );
+
+    // C function void glDrawElementsInstanced ( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instanceCount )
+
+    public static native void glDrawElementsInstanced(
+        int mode,
+        int count,
+        int type,
+        java.nio.Buffer indices,
+        int instanceCount
+    );
+
+    // C function void glDrawElementsInstanced ( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instanceCount )
+
+    public static native void glDrawElementsInstanced(
+        int mode,
+        int count,
+        int type,
+        int indicesOffset,
+        int instanceCount
+    );
+
+    // C function GLsync glFenceSync ( GLenum condition, GLbitfield flags )
+
+    public static native long glFenceSync(
+        int condition,
+        int flags
+    );
+
+    // C function GLboolean glIsSync ( GLsync sync )
+
+    public static native boolean glIsSync(
+        long sync
+    );
+
+    // C function void glDeleteSync ( GLsync sync )
+
+    public static native void glDeleteSync(
+        long sync
+    );
+
+    // C function GLenum glClientWaitSync ( GLsync sync, GLbitfield flags, GLuint64 timeout )
+
+    public static native int glClientWaitSync(
+        long sync,
+        int flags,
+        long timeout
+    );
+
+    // C function void glWaitSync ( GLsync sync, GLbitfield flags, GLuint64 timeout )
+
+    public static native void glWaitSync(
+        long sync,
+        int flags,
+        long timeout
+    );
+
+    // C function void glGetInteger64v ( GLenum pname, GLint64 *params )
+
+    public static native void glGetInteger64v(
+        int pname,
+        long[] params,
+        int offset
+    );
+
+    // C function void glGetInteger64v ( GLenum pname, GLint64 *params )
+
+    public static native void glGetInteger64v(
+        int pname,
+        java.nio.LongBuffer params
+    );
+
+    // C function void glGetSynciv ( GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values )
+
+    public static native void glGetSynciv(
+        long sync,
+        int pname,
+        int bufSize,
+        int[] length,
+        int lengthOffset,
+        int[] values,
+        int valuesOffset
+    );
+
+    // C function void glGetSynciv ( GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values )
+
+    public static native void glGetSynciv(
+        long sync,
+        int pname,
+        int bufSize,
+        java.nio.IntBuffer length,
+        java.nio.IntBuffer values
+    );
+
+    // C function void glGetInteger64i_v ( GLenum target, GLuint index, GLint64 *data )
+
+    public static native void glGetInteger64i_v(
+        int target,
+        int index,
+        long[] data,
+        int offset
+    );
+
+    // C function void glGetInteger64i_v ( GLenum target, GLuint index, GLint64 *data )
+
+    public static native void glGetInteger64i_v(
+        int target,
+        int index,
+        java.nio.LongBuffer data
+    );
+
+    // C function void glGetBufferParameteri64v ( GLenum target, GLenum pname, GLint64 *params )
+
+    public static native void glGetBufferParameteri64v(
+        int target,
+        int pname,
+        long[] params,
+        int offset
+    );
+
+    // C function void glGetBufferParameteri64v ( GLenum target, GLenum pname, GLint64 *params )
+
+    public static native void glGetBufferParameteri64v(
+        int target,
+        int pname,
+        java.nio.LongBuffer params
+    );
+
+    // C function void glGenSamplers ( GLsizei count, GLuint *samplers )
+
+    public static native void glGenSamplers(
+        int count,
+        int[] samplers,
+        int offset
+    );
+
+    // C function void glGenSamplers ( GLsizei count, GLuint *samplers )
+
+    public static native void glGenSamplers(
+        int count,
+        java.nio.IntBuffer samplers
+    );
+
+    // C function void glDeleteSamplers ( GLsizei count, const GLuint *samplers )
+
+    public static native void glDeleteSamplers(
+        int count,
+        int[] samplers,
+        int offset
+    );
+
+    // C function void glDeleteSamplers ( GLsizei count, const GLuint *samplers )
+
+    public static native void glDeleteSamplers(
+        int count,
+        java.nio.IntBuffer samplers
+    );
+
+    // C function GLboolean glIsSampler ( GLuint sampler )
+
+    public static native boolean glIsSampler(
+        int sampler
+    );
+
+    // C function void glBindSampler ( GLuint unit, GLuint sampler )
+
+    public static native void glBindSampler(
+        int unit,
+        int sampler
+    );
+
+    // C function void glSamplerParameteri ( GLuint sampler, GLenum pname, GLint param )
+
+    public static native void glSamplerParameteri(
+        int sampler,
+        int pname,
+        int param
+    );
+
+    // C function void glSamplerParameteriv ( GLuint sampler, GLenum pname, const GLint *param )
+
+    public static native void glSamplerParameteriv(
+        int sampler,
+        int pname,
+        int[] param,
+        int offset
+    );
+
+    // C function void glSamplerParameteriv ( GLuint sampler, GLenum pname, const GLint *param )
+
+    public static native void glSamplerParameteriv(
+        int sampler,
+        int pname,
+        java.nio.IntBuffer param
+    );
+
+    // C function void glSamplerParameterf ( GLuint sampler, GLenum pname, GLfloat param )
+
+    public static native void glSamplerParameterf(
+        int sampler,
+        int pname,
+        float param
+    );
+
+    // C function void glSamplerParameterfv ( GLuint sampler, GLenum pname, const GLfloat *param )
+
+    public static native void glSamplerParameterfv(
+        int sampler,
+        int pname,
+        float[] param,
+        int offset
+    );
+
+    // C function void glSamplerParameterfv ( GLuint sampler, GLenum pname, const GLfloat *param )
+
+    public static native void glSamplerParameterfv(
+        int sampler,
+        int pname,
+        java.nio.FloatBuffer param
+    );
+
+    // C function void glGetSamplerParameteriv ( GLuint sampler, GLenum pname, GLint *params )
+
+    public static native void glGetSamplerParameteriv(
+        int sampler,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    // C function void glGetSamplerParameteriv ( GLuint sampler, GLenum pname, GLint *params )
+
+    public static native void glGetSamplerParameteriv(
+        int sampler,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    // C function void glGetSamplerParameterfv ( GLuint sampler, GLenum pname, GLfloat *params )
+
+    public static native void glGetSamplerParameterfv(
+        int sampler,
+        int pname,
+        float[] params,
+        int offset
+    );
+
+    // C function void glGetSamplerParameterfv ( GLuint sampler, GLenum pname, GLfloat *params )
+
+    public static native void glGetSamplerParameterfv(
+        int sampler,
+        int pname,
+        java.nio.FloatBuffer params
+    );
+
+    // C function void glVertexAttribDivisor ( GLuint index, GLuint divisor )
+
+    public static native void glVertexAttribDivisor(
+        int index,
+        int divisor
+    );
+
+    // C function void glBindTransformFeedback ( GLenum target, GLuint id )
+
+    public static native void glBindTransformFeedback(
+        int target,
+        int id
+    );
+
+    // C function void glDeleteTransformFeedbacks ( GLsizei n, const GLuint *ids )
+
+    public static native void glDeleteTransformFeedbacks(
+        int n,
+        int[] ids,
+        int offset
+    );
+
+    // C function void glDeleteTransformFeedbacks ( GLsizei n, const GLuint *ids )
+
+    public static native void glDeleteTransformFeedbacks(
+        int n,
+        java.nio.IntBuffer ids
+    );
+
+    // C function void glGenTransformFeedbacks ( GLsizei n, GLuint *ids )
+
+    public static native void glGenTransformFeedbacks(
+        int n,
+        int[] ids,
+        int offset
+    );
+
+    // C function void glGenTransformFeedbacks ( GLsizei n, GLuint *ids )
+
+    public static native void glGenTransformFeedbacks(
+        int n,
+        java.nio.IntBuffer ids
+    );
+
+    // C function GLboolean glIsTransformFeedback ( GLuint id )
+
+    public static native boolean glIsTransformFeedback(
+        int id
+    );
+
+    // C function void glPauseTransformFeedback ( void )
+
+    public static native void glPauseTransformFeedback(
+    );
+
+    // C function void glResumeTransformFeedback ( void )
+
+    public static native void glResumeTransformFeedback(
+    );
+
+    // C function void glGetProgramBinary ( GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary )
+
+    public static native void glGetProgramBinary(
+        int program,
+        int bufSize,
+        int[] length,
+        int lengthOffset,
+        int[] binaryFormat,
+        int binaryFormatOffset,
+        java.nio.Buffer binary
+    );
+
+    // C function void glGetProgramBinary ( GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary )
+
+    public static native void glGetProgramBinary(
+        int program,
+        int bufSize,
+        java.nio.IntBuffer length,
+        java.nio.IntBuffer binaryFormat,
+        java.nio.Buffer binary
+    );
+
+    // C function void glProgramBinary ( GLuint program, GLenum binaryFormat, const GLvoid *binary, GLsizei length )
+
+    public static native void glProgramBinary(
+        int program,
+        int binaryFormat,
+        java.nio.Buffer binary,
+        int length
+    );
+
+    // C function void glProgramParameteri ( GLuint program, GLenum pname, GLint value )
+
+    public static native void glProgramParameteri(
+        int program,
+        int pname,
+        int value
+    );
+
+    // C function void glInvalidateFramebuffer ( GLenum target, GLsizei numAttachments, const GLenum *attachments )
+
+    public static native void glInvalidateFramebuffer(
+        int target,
+        int numAttachments,
+        int[] attachments,
+        int offset
+    );
+
+    // C function void glInvalidateFramebuffer ( GLenum target, GLsizei numAttachments, const GLenum *attachments )
+
+    public static native void glInvalidateFramebuffer(
+        int target,
+        int numAttachments,
+        java.nio.IntBuffer attachments
+    );
+
+    // C function void glInvalidateSubFramebuffer ( GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height )
+
+    public static native void glInvalidateSubFramebuffer(
+        int target,
+        int numAttachments,
+        int[] attachments,
+        int offset,
+        int x,
+        int y,
+        int width,
+        int height
+    );
+
+    // C function void glInvalidateSubFramebuffer ( GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height )
+
+    public static native void glInvalidateSubFramebuffer(
+        int target,
+        int numAttachments,
+        java.nio.IntBuffer attachments,
+        int x,
+        int y,
+        int width,
+        int height
+    );
+
+    // C function void glTexStorage2D ( GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height )
+
+    public static native void glTexStorage2D(
+        int target,
+        int levels,
+        int internalformat,
+        int width,
+        int height
+    );
+
+    // C function void glTexStorage3D ( GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth )
+
+    public static native void glTexStorage3D(
+        int target,
+        int levels,
+        int internalformat,
+        int width,
+        int height,
+        int depth
+    );
+
+    // C function void glGetInternalformativ ( GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params )
+
+    public static native void glGetInternalformativ(
+        int target,
+        int internalformat,
+        int pname,
+        int bufSize,
+        int[] params,
+        int offset
+    );
+
+    // C function void glGetInternalformativ ( GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params )
+
+    public static native void glGetInternalformativ(
+        int target,
+        int internalformat,
+        int pname,
+        int bufSize,
+        java.nio.IntBuffer params
+    );
+
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java
index 55e8c7c..3e499b2 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java
@@ -150,7 +150,9 @@
     public void onResume(int reason) {
         if (DEBUG) Log.d(TAG, "onResume()");
         mIsShowing = KeyguardUpdateMonitor.getInstance(mContext).isKeyguardVisible();
-        maybeStartBiometricUnlock();
+        if (!KeyguardUpdateMonitor.getInstance(mContext).isSwitchingUser()) {
+          maybeStartBiometricUnlock();
+        }
         KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateCallback);
 
         // Registers a callback which handles stopping the biometric unlock and restarting it in
@@ -268,6 +270,14 @@
         }
 
         @Override
+        public void onUserSwitchComplete(int userId) {
+            if (DEBUG) Log.d(TAG, "onUserSwitchComplete(" + userId + ")");
+            if (mBiometricUnlock != null) {
+                maybeStartBiometricUnlock();
+            }
+        }
+
+        @Override
         public void onKeyguardVisibilityChanged(boolean showing) {
             if (DEBUG) Log.d(TAG, "onKeyguardVisibilityChanged(" + showing + ")");
             boolean wasShowing = false;
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index d45048f..79d01dd 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -122,6 +122,8 @@
             mCallbacks = Lists.newArrayList();
     private ContentObserver mDeviceProvisionedObserver;
 
+    private boolean mSwitchingUser;
+
     private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
@@ -459,11 +461,13 @@
                         public void onUserSwitching(int newUserId, IRemoteCallback reply) {
                             mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHING,
                                     newUserId, 0, reply));
+                            mSwitchingUser = true;
                         }
                         @Override
                         public void onUserSwitchComplete(int newUserId) throws RemoteException {
                             mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCH_COMPLETE,
                                     newUserId));
+                            mSwitchingUser = false;
                         }
                     });
         } catch (RemoteException e) {
@@ -527,7 +531,6 @@
                 cb.onUserSwitching(userId);
             }
         }
-        setAlternateUnlockEnabled(false);
         try {
             reply.sendResult(null);
         } catch (RemoteException e) {
@@ -731,6 +734,10 @@
         return mKeyguardIsVisible;
     }
 
+    public boolean isSwitchingUser() {
+        return mSwitchingUser;
+    }
+
     private static boolean isBatteryUpdateInteresting(BatteryStatus old, BatteryStatus current) {
         final boolean nowPluggedIn = current.isPluggedIn();
         final boolean wasPluggedIn = old.isPluggedIn();
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
index 8232ca3..78ff3a8 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
@@ -324,8 +324,9 @@
                 mSwitchingUser = true;
                 resetStateLocked(null);
                 adjustStatusBarLocked();
-                // Disable face unlock when the user switches.
-                KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(false);
+                // When we switch users we want to bring the new user to the biometric unlock even
+                // if the current user has gone to the backup.
+                KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
             }
         }
 
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_airplane.xml b/packages/SystemUI/res/layout/quick_settings_tile_airplane.xml
deleted file mode 100644
index ac87496..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_airplane.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<TextView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/TextAppearance.QuickSettings.TileView"
-    android:id="@+id/airplane_mode_textview"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_gravity="center"
-    android:gravity="center"
-    />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_alarm.xml b/packages/SystemUI/res/layout/quick_settings_tile_alarm.xml
index 0327bee..493c704 100644
--- a/packages/SystemUI/res/layout/quick_settings_tile_alarm.xml
+++ b/packages/SystemUI/res/layout/quick_settings_tile_alarm.xml
@@ -15,11 +15,11 @@
 -->
 <TextView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/TextAppearance.QuickSettings.TileView"
+    style="@style/TextAppearance.QuickSettings.TileView.AllInOne"
     android:id="@+id/alarm_textview"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_gravity="center"
     android:gravity="center"
     android:drawableTop="@drawable/ic_qs_alarm_on"
-    />
\ No newline at end of file
+    />
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_basic.xml b/packages/SystemUI/res/layout/quick_settings_tile_basic.xml
new file mode 100644
index 0000000..16bf49c
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_basic.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_gravity="top"
+    android:orientation="vertical">
+    <ImageView
+        android:id="@+id/image"
+        android:layout_marginTop="@dimen/qs_tile_margin_above_icon"
+        android:layout_marginBottom="@dimen/qs_tile_margin_below_icon"
+        android:layout_width="@dimen/qs_tile_icon_size"
+        android:layout_height="@dimen/qs_tile_icon_size"
+        android:layout_gravity="top|center_horizontal"
+        android:scaleType="centerInside"
+        />
+    <TextView
+        style="@style/TextAppearance.QuickSettings.TileView"
+        android:id="@+id/text"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="top|center_horizontal"
+        android:gravity="top|center_horizontal"
+        />
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_battery.xml b/packages/SystemUI/res/layout/quick_settings_tile_battery.xml
index 446b24c..c41e9b9 100644
--- a/packages/SystemUI/res/layout/quick_settings_tile_battery.xml
+++ b/packages/SystemUI/res/layout/quick_settings_tile_battery.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
+<!-- Copyright (C) 2013 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.
@@ -14,24 +14,26 @@
      limitations under the License.
 -->
 <LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_gravity="center"
-    android:orientation="vertical">
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_gravity="top"
+        android:orientation="vertical">
     <ImageView
-        android:id="@+id/battery_image"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        android:paddingBottom="10dp"
-        />
+            android:id="@+id/image"
+            android:layout_marginTop="@dimen/qs_tile_margin_above_icon"
+            android:layout_marginBottom="@dimen/qs_tile_margin_below_icon"
+            android:layout_width="@dimen/qs_tile_icon_size"
+            android:layout_height="@dimen/qs_tile_icon_size"
+            android:layout_gravity="top|center_horizontal"
+            android:scaleType="centerInside"
+            />
     <TextView
-        style="@style/TextAppearance.QuickSettings.TileView"
-        android:id="@+id/battery_textview"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        android:gravity="center"
-        />
+            style="@style/TextAppearance.QuickSettings.TileView"
+            android:id="@+id/text"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="top|center_horizontal"
+            android:gravity="top|center_horizontal"
+            />
 </LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_bluetooth.xml b/packages/SystemUI/res/layout/quick_settings_tile_bluetooth.xml
deleted file mode 100644
index 2f3a9c6..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_bluetooth.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<TextView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/TextAppearance.QuickSettings.TileView"
-    android:id="@+id/bluetooth_textview"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_gravity="center"
-    android:gravity="center"
-    />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_brightness.xml b/packages/SystemUI/res/layout/quick_settings_tile_brightness.xml
deleted file mode 100644
index 5b3ce1f..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_brightness.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<TextView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/TextAppearance.QuickSettings.TileView"
-    android:id="@+id/brightness_textview"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_gravity="center"
-    android:gravity="center"
-    android:drawableTop="@drawable/ic_qs_brightness_auto_off"
-    />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_bugreport.xml b/packages/SystemUI/res/layout/quick_settings_tile_bugreport.xml
deleted file mode 100644
index 0b6a614..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_bugreport.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<TextView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/TextAppearance.QuickSettings.TileView"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_gravity="center"
-    android:gravity="center"
-    android:drawableTop="@*android:drawable/stat_sys_adb"
-    android:text="@*android:string/bugreport_title"
-    />
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_ime.xml b/packages/SystemUI/res/layout/quick_settings_tile_ime.xml
index e92acd5..1a31efa5 100644
--- a/packages/SystemUI/res/layout/quick_settings_tile_ime.xml
+++ b/packages/SystemUI/res/layout/quick_settings_tile_ime.xml
@@ -15,7 +15,7 @@
 -->
 <TextView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/TextAppearance.QuickSettings.TileView"
+    style="@style/TextAppearance.QuickSettings.TileView.AllInOne"
     android:id="@+id/ime_textview"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
@@ -23,4 +23,4 @@
     android:gravity="center"
     android:drawableTop="@drawable/ic_qs_ime"
     android:text="@string/quick_settings_ime_label"
-    />
\ No newline at end of file
+    />
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_location.xml b/packages/SystemUI/res/layout/quick_settings_tile_location.xml
deleted file mode 100644
index 0accb38..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_location.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<TextView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/TextAppearance.QuickSettings.TileView"
-    android:id="@+id/location_textview"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_gravity="center"
-    android:gravity="center"
-    android:drawableTop="@drawable/ic_qs_location"
-    android:text="@string/quick_settings_location_label"
-    />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_media.xml b/packages/SystemUI/res/layout/quick_settings_tile_media.xml
index 7217de3..355176c6 100644
--- a/packages/SystemUI/res/layout/quick_settings_tile_media.xml
+++ b/packages/SystemUI/res/layout/quick_settings_tile_media.xml
@@ -15,10 +15,10 @@
 -->
 <TextView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/TextAppearance.QuickSettings.TileView"
+    style="@style/TextAppearance.QuickSettings.TileView.AllInOne"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:gravity="center"
     android:text="@string/quick_settings_media_device_label"
     android:singleLine="true"
-    />
\ No newline at end of file
+    />
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_rotation_lock.xml b/packages/SystemUI/res/layout/quick_settings_tile_rotation_lock.xml
deleted file mode 100644
index 6aecaea..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_rotation_lock.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<TextView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/TextAppearance.QuickSettings.TileView"
-    android:id="@+id/rotation_lock_textview"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_gravity="center"
-    android:gravity="center"
-    />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml b/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml
index febd8a8..34506b1 100644
--- a/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml
+++ b/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml
@@ -15,27 +15,28 @@
 -->
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_gravity="center"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_gravity="top"
     android:orientation="vertical">
     <FrameLayout
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center">
+        android:layout_marginTop="@dimen/qs_tile_margin_above_icon"
+        android:layout_marginBottom="@dimen/qs_tile_margin_below_icon"
+        android:layout_width="@dimen/qs_tile_icon_size"
+        android:layout_height="@dimen/qs_tile_icon_size"
+        android:layout_gravity="top|center_horizontal"
+        >
         <ImageView
             android:id="@+id/rssi_image"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="center"
-            android:paddingBottom="10dp"
             />
         <ImageView
             android:id="@+id/rssi_overlay_image"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="center"
-            android:paddingBottom="10dp"
             />
     </FrameLayout>
     <TextView
@@ -43,8 +44,8 @@
         android:id="@+id/rssi_textview"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        android:gravity="center"
+        android:layout_gravity="top|center_horizontal"
+        android:gravity="top|center_horizontal"
         android:text="@string/quick_settings_rssi_label"
         />
 </LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_settings.xml b/packages/SystemUI/res/layout/quick_settings_tile_settings.xml
deleted file mode 100644
index d155935..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_settings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<TextView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/TextAppearance.QuickSettings.TileView"
-    android:id="@+id/settings_tileview"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_gravity="center"
-    android:gravity="center"
-    android:drawableTop="@drawable/ic_qs_settings"
-    />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_user.xml b/packages/SystemUI/res/layout/quick_settings_tile_user.xml
index 878f500..80fc685 100644
--- a/packages/SystemUI/res/layout/quick_settings_tile_user.xml
+++ b/packages/SystemUI/res/layout/quick_settings_tile_user.xml
@@ -25,13 +25,12 @@
         android:scaleType="centerCrop"
         />
     <TextView
-        style="@style/TextAppearance.QuickSettings.TileView"
+        style="@style/TextAppearance.QuickSettings.TileView.User"
         android:id="@+id/user_textview"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_gravity="center_horizontal|bottom"
         android:gravity="center"
         android:text="@string/quick_settings_user_label"
-        android:background="#CC000000"
         />
 </FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_wifi.xml b/packages/SystemUI/res/layout/quick_settings_tile_wifi.xml
deleted file mode 100644
index 67d6c23..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_wifi.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<TextView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/TextAppearance.QuickSettings.TileView"
-    android:id="@+id/wifi_textview"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_gravity="center"
-    android:gravity="center"
-    android:text="@string/quick_settings_wifi_label"
-    />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_wifi_display.xml b/packages/SystemUI/res/layout/quick_settings_tile_wifi_display.xml
deleted file mode 100644
index 2d7e441..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_wifi_display.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<TextView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/TextAppearance.QuickSettings.TileView"
-    android:id="@+id/wifi_display_textview"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_gravity="center"
-    android:gravity="center"
-    android:drawableTop="@drawable/ic_qs_remote_display"
-    android:text="@string/quick_settings_wifi_display_label"
-    />
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index ed08115..f90f08a 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -205,4 +205,11 @@
     <!-- How far to slide the panel out when you touch it -->
     <!-- For phones, this is close_handle_height + header_height -->
     <dimen name="peek_height">84dp</dimen>
+
+    <!-- Quick Settings tile geometry: top interior margin, above icon -->
+    <dimen name="qs_tile_margin_above_icon">27dp</dimen>
+    <!-- Quick Settings tile geometry: gap between icon and text -->
+    <dimen name="qs_tile_margin_below_icon">17dp</dimen>
+    <!-- Quick Settings tile geometry: icon size -->
+    <dimen name="qs_tile_icon_size">32dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 1a59d6c..7ddf261 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -92,17 +92,20 @@
     <style name="TextAppearance.QuickSettings" />
 
     <style name="TextAppearance.QuickSettings.TileView">
-        <item name="android:paddingLeft">6dp</item>
-        <item name="android:paddingRight">6dp</item>
-        <item name="android:paddingBottom">2dp</item>
-        <item name="android:drawablePadding">12dp</item>
         <item name="android:textSize">12dp</item>
         <item name="android:textStyle">normal</item>
         <item name="android:textColor">#CCCCCC</item>
         <item name="android:textAllCaps">true</item>
-        <item name="android:singleLine">true</item>
-        <item name="android:ellipsize">marquee</item>
-        <item name="android:fadingEdge">horizontal</item>
+        <item name="android:paddingStart">6dp</item>
+        <item name="android:paddingEnd">6dp</item>
+    </style>
+
+    <style name="TextAppearance.QuickSettings.TileView.AllInOne" parent="@style/TextAppearance.QuickSettings.TileView">
+        <item name="android:lines">2</item>
+        <item name="android:gravity">top</item>
+        <item name="android:paddingBottom">2dp</item>
+        <item name="android:paddingTop">16dp</item>
+        <item name="android:drawablePadding">8dp</item>
     </style>
 
     <style name="TextAppearance.QuickSettings.Clock" parent="@style/TextAppearance.QuickSettings.TileView">
@@ -119,6 +122,13 @@
         <item name="android:textColor">#ff3a3b39</item>
     </style>
 
+    <style name="TextAppearance.QuickSettings.TileView.User" parent="@style/TextAppearance.QuickSettings.TileView">
+        <item name="android:background">#CC000000</item>
+        <item name="android:padding">4dp</item>
+        <item name="android:singleLine">true</item>
+        <item name="android:fadingEdge">horizontal</item>
+    </style>
+
     <style name="BaseBrightnessDialogContainer">
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">wrap_content</item>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index d98f08e..498d869 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -132,6 +132,9 @@
     private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10; // see NotificationManagerService
     private static final int HIDE_ICONS_BELOW_SCORE = Notification.PRIORITY_LOW * NOTIFICATION_PRIORITY_MULTIPLIER;
 
+    private static final long AUTOHIDE_TIMEOUT_MS = 3000;
+    private static final float TRANSPARENT_ALPHA = 0.7f;
+
     // fling gesture tuning parameters, scaled to display density
     private float mSelfExpandVelocityPx; // classic value: 2000px/s
     private float mSelfCollapseVelocityPx; // classic value: 2000px/s (will be negated to collapse "up")
@@ -304,6 +307,15 @@
         }
     };
 
+    private boolean mAutohideSuspended;
+
+    private final Runnable mAutohide = new Runnable() {
+        @Override
+        public void run() {
+            int requested = mSystemUiVisibility & ~View.STATUS_BAR_OVERLAY;
+            notifyUiVisibilityChanged(requested);
+        }};
+
     @Override
     public void start() {
         mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
@@ -1384,6 +1396,8 @@
         }
 
         visibilityChanged(true);
+
+        suspendAutohide();
     }
 
     public void animateCollapsePanels() {
@@ -1666,6 +1680,11 @@
             mPostCollapseCleanup.run();
             mPostCollapseCleanup = null;
         }
+
+        // Reschedule suspended auto-hide if necessary
+        if (mAutohideSuspended) {
+            scheduleAutohide();
+        }
     }
 
     /**
@@ -1812,6 +1831,7 @@
             hideCling();
         }
 
+        suspendAutohide();
         return false;
     }
 
@@ -1855,10 +1875,41 @@
                 setStatusBarLowProfile(lightsOut);
             }
 
-            notifyUiVisibilityChanged();
+            if (0 != (diff & View.STATUS_BAR_OVERLAY)) {
+                boolean overlay = 0 != (vis & View.STATUS_BAR_OVERLAY);
+                if (overlay) {
+                    setTransparent(true);
+                    scheduleAutohide();
+                } else {
+                    setTransparent(false);
+                    cancelAutohide();
+                }
+            }
+            notifyUiVisibilityChanged(mSystemUiVisibility);
         }
     }
 
+    private void suspendAutohide() {
+        mHandler.removeCallbacks(mAutohide);
+        mAutohideSuspended = (0 != (mSystemUiVisibility & View.STATUS_BAR_OVERLAY));
+    }
+
+    private void cancelAutohide() {
+        mAutohideSuspended = false;
+        mHandler.removeCallbacks(mAutohide);
+    }
+
+    private void scheduleAutohide() {
+        cancelAutohide();
+        mHandler.postDelayed(mAutohide, AUTOHIDE_TIMEOUT_MS);
+    }
+
+    private void setTransparent(boolean transparent) {
+        float alpha = transparent ? TRANSPARENT_ALPHA : 1;
+        if (DEBUG) Slog.d(TAG, "Setting alpha to " + alpha);
+        mStatusBarView.setAlpha(alpha);
+    }
+
     private void setStatusBarLowProfile(boolean lightsOut) {
         if (mLightsOutAnimation == null) {
             final View notifications = mStatusBarView.findViewById(R.id.notification_icon_area);
@@ -1913,9 +1964,9 @@
         }
     }
 
-    private void notifyUiVisibilityChanged() {
+    private void notifyUiVisibilityChanged(int vis) {
         try {
-            mWindowManagerService.statusBarVisibilityChanged(mSystemUiVisibility);
+            mWindowManagerService.statusBarVisibilityChanged(vis);
         } catch (RemoteException ex) {
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
index a7c7fba..d826282 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.phone;
 
 import com.android.internal.view.RotationPolicy;
-import com.android.internal.widget.LockPatternUtils;
 import com.android.systemui.R;
 
 import com.android.systemui.statusbar.phone.QuickSettingsModel.BluetoothState;
@@ -38,7 +37,6 @@
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.CursorLoader;
 import android.content.DialogInterface;
 import android.content.DialogInterface.OnClickListener;
 import android.content.Intent;
@@ -80,6 +78,7 @@
  *
  */
 class QuickSettings {
+    static final boolean DEBUG_GONE_TILES = false;
     private static final String TAG = "QuickSettings";
     public static final boolean SHOW_IME_TILE = false;
 
@@ -271,6 +270,10 @@
         startSettingsActivity(intent, true);
     }
 
+    private void collapsePanels() {
+        getService().animateCollapsePanels();
+    }
+
     private void startSettingsActivity(Intent intent, boolean onlyProvisioned) {
         if (onlyProvisioned && !getService().isDeviceProvisioned()) return;
         try {
@@ -280,7 +283,7 @@
         }
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
         mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
-        getService().animateCollapsePanels();
+        collapsePanels();
     }
 
     private void addUserTiles(ViewGroup parent, LayoutInflater inflater) {
@@ -290,7 +293,7 @@
         userTile.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                mBar.collapseAllPanels(true);
+                collapsePanels();
                 final UserManager um = UserManager.get(mContext);
                 if (um.getUsers(true).size() > 1) {
                     try {
@@ -322,24 +325,18 @@
         mDynamicSpannedTiles.add(userTile);
 
         // Brightness
-        QuickSettingsTileView brightnessTile = (QuickSettingsTileView)
-                inflater.inflate(R.layout.quick_settings_tile, parent, false);
-        brightnessTile.setContent(R.layout.quick_settings_tile_brightness, inflater);
+        final QuickSettingsBasicTile brightnessTile
+                = new QuickSettingsBasicTile(mContext);
+        brightnessTile.setImageResource(R.drawable.ic_qs_brightness_auto_off);
         brightnessTile.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                mBar.collapseAllPanels(true);
+                collapsePanels();
                 showBrightnessDialog();
             }
         });
-        mModel.addBrightnessTile(brightnessTile, new QuickSettingsModel.RefreshCallback() {
-            @Override
-            public void refreshView(QuickSettingsTileView view, State state) {
-                TextView tv = (TextView) view.findViewById(R.id.brightness_textview);
-                tv.setCompoundDrawablesWithIntrinsicBounds(0, state.iconId, 0, 0);
-                tv.setText(state.label);
-            }
-        });
+        mModel.addBrightnessTile(brightnessTile,
+                new QuickSettingsModel.BasicRefreshCallback(brightnessTile));
         parent.addView(brightnessTile);
         mDynamicSpannedTiles.add(brightnessTile);
 
@@ -364,31 +361,24 @@
         */
 
         // Settings tile
-        QuickSettingsTileView settingsTile = (QuickSettingsTileView)
-                inflater.inflate(R.layout.quick_settings_tile, parent, false);
-        settingsTile.setContent(R.layout.quick_settings_tile_settings, inflater);
+        final QuickSettingsBasicTile settingsTile = new QuickSettingsBasicTile(mContext);
+        settingsTile.setImageResource(R.drawable.ic_qs_settings);
         settingsTile.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                 startSettingsActivity(android.provider.Settings.ACTION_SETTINGS);
             }
         });
-        mModel.addSettingsTile(settingsTile, new QuickSettingsModel.RefreshCallback() {
-            @Override
-            public void refreshView(QuickSettingsTileView view, State state) {
-                TextView tv = (TextView) view.findViewById(R.id.settings_tileview);
-                tv.setText(state.label);
-            }
-        });
+        mModel.addSettingsTile(settingsTile,
+                new QuickSettingsModel.BasicRefreshCallback(settingsTile));
         parent.addView(settingsTile);
         mDynamicSpannedTiles.add(settingsTile);
     }
 
     private void addSystemTiles(ViewGroup parent, LayoutInflater inflater) {
         // Wi-fi
-        final QuickSettingsTileView wifiTile = (QuickSettingsTileView)
-                inflater.inflate(R.layout.quick_settings_tile, parent, false);
-        wifiTile.setContent(R.layout.quick_settings_tile_wifi, inflater);
+        final QuickSettingsBasicTile wifiTile
+                = new QuickSettingsBasicTile(mContext);
         wifiTile.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
@@ -421,12 +411,11 @@
         }
         mModel.addWifiTile(wifiTile, new QuickSettingsModel.RefreshCallback() {
             @Override
-            public void refreshView(QuickSettingsTileView view, State state) {
+            public void refreshView(QuickSettingsTileView unused, State state) {
                 WifiState wifiState = (WifiState) state;
-                TextView tv = (TextView) view.findViewById(R.id.wifi_textview);
-                tv.setCompoundDrawablesWithIntrinsicBounds(0, wifiState.iconId, 0, 0);
-                tv.setText(wifiState.label);
-                view.setContentDescription(mContext.getString(
+                wifiTile.setImageResource(wifiState.iconId);
+                wifiTile.setText(wifiState.label);
+                wifiTile.setContentDescription(mContext.getString(
                         R.string.accessibility_quick_settings_wifi,
                         wifiState.signalContentDescription,
                         (wifiState.connected) ? wifiState.label : ""));
@@ -476,10 +465,10 @@
         }
 
         // Rotation Lock
-        if (mContext.getResources().getBoolean(R.bool.quick_settings_show_rotation_lock)) {
-            QuickSettingsTileView rotationLockTile = (QuickSettingsTileView)
-                    inflater.inflate(R.layout.quick_settings_tile, parent, false);
-            rotationLockTile.setContent(R.layout.quick_settings_tile_rotation_lock, inflater);
+        if (mContext.getResources().getBoolean(R.bool.quick_settings_show_rotation_lock)
+                || DEBUG_GONE_TILES) {
+            final QuickSettingsBasicTile rotationLockTile
+                    = new QuickSettingsBasicTile(mContext);
             rotationLockTile.setOnClickListener(new View.OnClickListener() {
                 @Override
                 public void onClick(View v) {
@@ -487,21 +476,13 @@
                     RotationPolicy.setRotationLock(mContext, !locked);
                 }
             });
-            mModel.addRotationLockTile(rotationLockTile, new QuickSettingsModel.RefreshCallback() {
-                @Override
-                public void refreshView(QuickSettingsTileView view, State state) {
-                    TextView tv = (TextView) view.findViewById(R.id.rotation_lock_textview);
-                    tv.setCompoundDrawablesWithIntrinsicBounds(0, state.iconId, 0, 0);
-                    tv.setText(state.label);
-                }
-            });
+            mModel.addRotationLockTile(rotationLockTile,
+                    new QuickSettingsModel.BasicRefreshCallback(rotationLockTile));
             parent.addView(rotationLockTile);
         }
 
         // Battery
-        QuickSettingsTileView batteryTile = (QuickSettingsTileView)
-                inflater.inflate(R.layout.quick_settings_tile, parent, false);
-        batteryTile.setContent(R.layout.quick_settings_tile_battery, inflater);
+        final QuickSettingsBasicTile batteryTile = new QuickSettingsBasicTile(mContext);
         batteryTile.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
@@ -510,11 +491,9 @@
         });
         mModel.addBatteryTile(batteryTile, new QuickSettingsModel.RefreshCallback() {
             @Override
-            public void refreshView(QuickSettingsTileView view, State state) {
+            public void refreshView(QuickSettingsTileView unused, State state) {
                 QuickSettingsModel.BatteryState batteryState =
                         (QuickSettingsModel.BatteryState) state;
-                TextView tv = (TextView) view.findViewById(R.id.battery_textview);
-                ImageView iv = (ImageView) view.findViewById(R.id.battery_image);
                 Drawable d = batteryState.pluggedIn
                         ? mChargingBatteryLevels
                         : mBatteryLevels;
@@ -528,40 +507,38 @@
                         : mContext.getString(R.string.status_bar_settings_battery_meter_format,
                                 batteryState.batteryLevel);
                 }
-                iv.setImageDrawable(d);
-                iv.setImageLevel(batteryState.batteryLevel);
-                tv.setText(t);
-                view.setContentDescription(
+                d.setLevel(batteryState.batteryLevel);
+                batteryTile.setImageDrawable(d);
+                batteryTile.setText(t);
+                batteryTile.setContentDescription(
                         mContext.getString(R.string.accessibility_quick_settings_battery, t));
             }
         });
         parent.addView(batteryTile);
 
         // Airplane Mode
-        QuickSettingsTileView airplaneTile = (QuickSettingsTileView)
-                inflater.inflate(R.layout.quick_settings_tile, parent, false);
-        airplaneTile.setContent(R.layout.quick_settings_tile_airplane, inflater);
+        final QuickSettingsBasicTile airplaneTile
+                = new QuickSettingsBasicTile(mContext);
         mModel.addAirplaneModeTile(airplaneTile, new QuickSettingsModel.RefreshCallback() {
             @Override
-            public void refreshView(QuickSettingsTileView view, State state) {
-                TextView tv = (TextView) view.findViewById(R.id.airplane_mode_textview);
-                tv.setCompoundDrawablesWithIntrinsicBounds(0, state.iconId, 0, 0);
+            public void refreshView(QuickSettingsTileView unused, State state) {
+                airplaneTile.setImageResource(state.iconId);
 
                 String airplaneState = mContext.getString(
                         (state.enabled) ? R.string.accessibility_desc_on
                                 : R.string.accessibility_desc_off);
-                view.setContentDescription(
+                airplaneTile.setContentDescription(
                         mContext.getString(R.string.accessibility_quick_settings_airplane, airplaneState));
-                tv.setText(state.label);
+                airplaneTile.setText(state.label);
             }
         });
         parent.addView(airplaneTile);
 
         // Bluetooth
-        if (mModel.deviceSupportsBluetooth()) {
-            final QuickSettingsTileView bluetoothTile = (QuickSettingsTileView)
-                    inflater.inflate(R.layout.quick_settings_tile, parent, false);
-            bluetoothTile.setContent(R.layout.quick_settings_tile_bluetooth, inflater);
+        if (mModel.deviceSupportsBluetooth()
+                || DEBUG_GONE_TILES) {
+            final QuickSettingsBasicTile bluetoothTile
+                    = new QuickSettingsBasicTile(mContext);
             bluetoothTile.setOnClickListener(new View.OnClickListener() {
                 @Override
                 public void onClick(View v) {
@@ -583,14 +560,12 @@
             }
             mModel.addBluetoothTile(bluetoothTile, new QuickSettingsModel.RefreshCallback() {
                 @Override
-                public void refreshView(QuickSettingsTileView view, State state) {
+                public void refreshView(QuickSettingsTileView unused, State state) {
                     BluetoothState bluetoothState = (BluetoothState) state;
-                    TextView tv = (TextView) view.findViewById(R.id.bluetooth_textview);
-                    tv.setCompoundDrawablesWithIntrinsicBounds(0, state.iconId, 0, 0);
+                    bluetoothTile.setImageResource(state.iconId);
 
-                    Resources r = mContext.getResources();
-                    String label = state.label;
                     /*
+                    Resources r = mContext.getResources();
                     //TODO: Show connected bluetooth device label
                     Set<BluetoothDevice> btDevices =
                             mBluetoothController.getBondedBluetoothDevices();
@@ -603,10 +578,10 @@
                                 btDevices.size());
                     }
                     */
-                    view.setContentDescription(mContext.getString(
+                    bluetoothTile.setContentDescription(mContext.getString(
                             R.string.accessibility_quick_settings_bluetooth,
                             bluetoothState.stateContentDescription));
-                    tv.setText(label);
+                    bluetoothTile.setText(state.label);
                 }
             });
             parent.addView(bluetoothTile);
@@ -616,9 +591,9 @@
 
     private void addTemporaryTiles(final ViewGroup parent, final LayoutInflater inflater) {
         // Alarm tile
-        QuickSettingsTileView alarmTile = (QuickSettingsTileView)
-                inflater.inflate(R.layout.quick_settings_tile, parent, false);
-        alarmTile.setContent(R.layout.quick_settings_tile_alarm, inflater);
+        final QuickSettingsBasicTile alarmTile
+                = new QuickSettingsBasicTile(mContext);
+        alarmTile.setImageResource(R.drawable.ic_qs_alarm_on);
         alarmTile.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
@@ -632,94 +607,77 @@
         });
         mModel.addAlarmTile(alarmTile, new QuickSettingsModel.RefreshCallback() {
             @Override
-            public void refreshView(QuickSettingsTileView view, State alarmState) {
-                TextView tv = (TextView) view.findViewById(R.id.alarm_textview);
-                tv.setText(alarmState.label);
-                view.setVisibility(alarmState.enabled ? View.VISIBLE : View.GONE);
-                view.setContentDescription(mContext.getString(
+            public void refreshView(QuickSettingsTileView unused, State alarmState) {
+                alarmTile.setText(alarmState.label);
+                alarmTile.setVisibility(alarmState.enabled ? View.VISIBLE : View.GONE);
+                alarmTile.setContentDescription(mContext.getString(
                         R.string.accessibility_quick_settings_alarm, alarmState.label));
             }
         });
         parent.addView(alarmTile);
 
         // Location
-        QuickSettingsTileView locationTile = (QuickSettingsTileView)
-                inflater.inflate(R.layout.quick_settings_tile, parent, false);
-        locationTile.setContent(R.layout.quick_settings_tile_location, inflater);
+        final QuickSettingsBasicTile locationTile
+                = new QuickSettingsBasicTile(mContext);
+        locationTile.setImageResource(R.drawable.ic_qs_location);
+        locationTile.setTextResource(R.string.quick_settings_location_label);
         locationTile.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                 startSettingsActivity(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
             }
         });
-        mModel.addLocationTile(locationTile, new QuickSettingsModel.RefreshCallback() {
-            @Override
-            public void refreshView(QuickSettingsTileView view, State state) {
-                TextView tv = (TextView) view.findViewById(R.id.location_textview);
-                tv.setText(state.label);
-                view.setVisibility(state.enabled ? View.VISIBLE : View.GONE);
-            }
-        });
+        mModel.addLocationTile(locationTile,
+                new QuickSettingsModel.BasicRefreshCallback(locationTile)
+                        .setShowWhenEnabled(true));
         parent.addView(locationTile);
 
         // Wifi Display
-        QuickSettingsTileView wifiDisplayTile = (QuickSettingsTileView)
-                inflater.inflate(R.layout.quick_settings_tile, parent, false);
-        wifiDisplayTile.setContent(R.layout.quick_settings_tile_wifi_display, inflater);
+        QuickSettingsBasicTile wifiDisplayTile
+                = new QuickSettingsBasicTile(mContext);
+        wifiDisplayTile.setImageResource(R.drawable.ic_qs_remote_display);
         wifiDisplayTile.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                 startSettingsActivity(android.provider.Settings.ACTION_WIFI_DISPLAY_SETTINGS);
             }
         });
-        mModel.addWifiDisplayTile(wifiDisplayTile, new QuickSettingsModel.RefreshCallback() {
-            @Override
-            public void refreshView(QuickSettingsTileView view, State state) {
-                TextView tv = (TextView) view.findViewById(R.id.wifi_display_textview);
-                tv.setText(state.label);
-                tv.setCompoundDrawablesWithIntrinsicBounds(0, state.iconId, 0, 0);
-                view.setVisibility(state.enabled ? View.VISIBLE : View.GONE);
-            }
-        });
+        mModel.addWifiDisplayTile(wifiDisplayTile,
+                new QuickSettingsModel.BasicRefreshCallback(wifiDisplayTile)
+                        .setShowWhenEnabled(true));
         parent.addView(wifiDisplayTile);
 
-        if (SHOW_IME_TILE) {
+        if (SHOW_IME_TILE || DEBUG_GONE_TILES) {
             // IME
-            QuickSettingsTileView imeTile = (QuickSettingsTileView)
-                    inflater.inflate(R.layout.quick_settings_tile, parent, false);
-            imeTile.setContent(R.layout.quick_settings_tile_ime, inflater);
+            final QuickSettingsBasicTile imeTile
+                    = new QuickSettingsBasicTile(mContext);
+            imeTile.setImageResource(R.drawable.ic_qs_ime);
             imeTile.setOnClickListener(new View.OnClickListener() {
                 @Override
                 public void onClick(View v) {
                     try {
-                        mBar.collapseAllPanels(true);
+                        collapsePanels();
                         Intent intent = new Intent(Settings.ACTION_SHOW_INPUT_METHOD_PICKER);
                         PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
                         pendingIntent.send();
                     } catch (Exception e) {}
                 }
             });
-            mModel.addImeTile(imeTile, new QuickSettingsModel.RefreshCallback() {
-                @Override
-                public void refreshView(QuickSettingsTileView view, State state) {
-                    TextView tv = (TextView) view.findViewById(R.id.ime_textview);
-                    if (state.label != null) {
-                        tv.setText(state.label);
-                    }
-                    view.setVisibility(state.enabled ? View.VISIBLE : View.GONE);
-                }
-            });
+            mModel.addImeTile(imeTile,
+                    new QuickSettingsModel.BasicRefreshCallback(imeTile)
+                            .setShowWhenEnabled(true));
             parent.addView(imeTile);
         }
 
         // Bug reports
-        QuickSettingsTileView bugreportTile = (QuickSettingsTileView)
-                inflater.inflate(R.layout.quick_settings_tile, parent, false);
-        bugreportTile.setContent(R.layout.quick_settings_tile_bugreport, inflater);
+        final QuickSettingsBasicTile bugreportTile
+                = new QuickSettingsBasicTile(mContext);
+        bugreportTile.setImageResource(com.android.internal.R.drawable.stat_sys_adb);
+        bugreportTile.setTextResource(com.android.internal.R.string.bugreport_title);
         bugreportTile.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                mBar.collapseAllPanels(true);
+                collapsePanels();
                 showBugreportDialog();
             }
         });
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsBasicTile.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsBasicTile.java
new file mode 100644
index 0000000..94b2fc7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsBasicTile.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2013 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.systemui.statusbar.phone;
+
+import com.android.systemui.R;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+class QuickSettingsBasicTile extends QuickSettingsTileView {
+    private final TextView mTextView;
+    private final ImageView mImageView;
+
+    public QuickSettingsBasicTile(Context context) {
+        this(context, null);
+    }
+
+    public QuickSettingsBasicTile(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        setLayoutParams(new FrameLayout.LayoutParams(
+            FrameLayout.LayoutParams.MATCH_PARENT,
+            context.getResources().getDimensionPixelSize(R.dimen.quick_settings_cell_height)
+        ));
+        setBackgroundResource(R.drawable.qs_tile_background);
+        addView(LayoutInflater.from(context).inflate(
+                R.layout.quick_settings_tile_basic, null),
+                new FrameLayout.LayoutParams(
+                        FrameLayout.LayoutParams.MATCH_PARENT,
+                        FrameLayout.LayoutParams.MATCH_PARENT));
+        mTextView = (TextView) findViewById(R.id.text);
+        mImageView = (ImageView) findViewById(R.id.image);
+    }
+
+    @Override
+    void setContent(int layoutId, LayoutInflater inflater) {
+        throw new RuntimeException("why?");
+    }
+
+    public ImageView getImageView() {
+        return mImageView;
+    }
+
+    public TextView getTextView() {
+        return mTextView;
+    }
+
+    public void setImageDrawable(Drawable drawable) {
+        mImageView.setImageDrawable(drawable);
+    }
+
+    public void setImageResource(int resId) {
+        mImageView.setImageResource(resId);
+    }
+
+    public void setText(CharSequence text) {
+        mTextView.setText(text);
+    }
+
+    public void setTextResource(int resId) {
+        mTextView.setText(resId);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
index 435ea4c..38c46c4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.phone;
 
-import android.app.ActivityManager;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback;
 import android.content.BroadcastReceiver;
@@ -96,6 +95,31 @@
         public void refreshView(QuickSettingsTileView view, State state);
     }
 
+    public static class BasicRefreshCallback implements RefreshCallback {
+        private final QuickSettingsBasicTile mView;
+        private boolean mShowWhenEnabled;
+
+        public BasicRefreshCallback(QuickSettingsBasicTile v) {
+            mView = v;
+        }
+        public void refreshView(QuickSettingsTileView ignored, State state) {
+            if (mShowWhenEnabled) {
+                mView.setVisibility(state.enabled ? View.VISIBLE : View.GONE);
+            }
+            if (state.iconId != 0) {
+                mView.setImageDrawable(null); // needed to flush any cached IDs
+                mView.setImageResource(state.iconId);
+            }
+            if (state.label != null) {
+                mView.setText(state.label);
+            }
+        }
+        public BasicRefreshCallback setShowWhenEnabled(boolean swe) {
+            mShowWhenEnabled = swe;
+            return this;
+        }
+    }
+
     /** Broadcast receive to determine if there is an alarm set. */
     private BroadcastReceiver mAlarmIntentReceiver = new BroadcastReceiver() {
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java
index 8f5cde6..9cff242 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
+import android.view.View;
 import android.widget.FrameLayout;
 
 /**
@@ -28,7 +29,6 @@
 
     private int mColSpan;
     private int mRowSpan;
-    private int mCellWidth;
 
     public QuickSettingsTileView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -48,4 +48,19 @@
     void setContent(int layoutId, LayoutInflater inflater) {
         inflater.inflate(layoutId, this);
     }
+
+    @Override
+    public void setVisibility(int vis) {
+        if (QuickSettings.DEBUG_GONE_TILES) {
+            if (vis == View.GONE) {
+                vis = View.VISIBLE;
+                setAlpha(0.25f);
+                setEnabled(false);
+            } else {
+                setAlpha(1f);
+                setEnabled(true);
+            }
+        }
+        super.setVisibility(vis);
+    }
 }
\ No newline at end of file
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index c089815..0f719db 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -145,6 +145,8 @@
     static public final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
     static public final String SYSTEM_DIALOG_REASON_ASSIST = "assist";
 
+    static public final String ACTION_HIDEYBARS = "android.intent.action.HIDEYBARS";
+
     /**
      * These are the system UI flags that, when changing, can cause the layout
      * of the screen to change.
@@ -543,6 +545,18 @@
     }
     MyOrientationListener mOrientationListener;
 
+    private static final int HIDEYBARS_NONE = 0;
+    private static final int HIDEYBARS_SHOWING = 1;
+    private static final int HIDEYBARS_HIDING = 2;
+    private int mHideybars;
+
+    BroadcastReceiver mHideybarsReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+           receivedHideybars(intent.getAction());
+        }
+    };
+
     IStatusBarService getStatusBarService() {
         synchronized (mServiceAquireLock) {
             if (mStatusBarService == null) {
@@ -891,6 +905,11 @@
         filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
         context.registerReceiver(mMultiuserReceiver, filter);
 
+        // register for hideybars
+        filter = new IntentFilter();
+        filter.addAction(ACTION_HIDEYBARS);
+        context.registerReceiver(mHideybarsReceiver, filter);
+
         mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
         mLongPressVibePattern = getLongIntArray(mContext.getResources(),
                 com.android.internal.R.array.config_longPressVibePattern);
@@ -2478,6 +2497,10 @@
 
     @Override
     public int adjustSystemUiVisibilityLw(int visibility) {
+        if (mHideybars == HIDEYBARS_SHOWING && 0 == (visibility & View.STATUS_BAR_OVERLAY)) {
+            mHideybars = HIDEYBARS_HIDING;
+            mStatusBar.hideLw(true);
+        }
         // Reset any bits in mForceClearingStatusBarVisibility that
         // are now clear.
         mResettingSystemUiFlags &= visibility;
@@ -2713,9 +2736,11 @@
                 // For layout, the status bar is always at the top with our fixed height.
                 mStableTop = mUnrestrictedScreenTop + mStatusBarHeight;
 
+                boolean statusBarOverlay = (mLastSystemUiFlags & View.STATUS_BAR_OVERLAY) != 0;
+
                 // If the status bar is hidden, we don't want to cause
                 // windows behind it to scroll.
-                if (mStatusBar.isVisibleLw()) {
+                if (mStatusBar.isVisibleLw() && !statusBarOverlay) {
                     // Status bar may go away, so the screen area it occupies
                     // is available to apps but just covering them when the
                     // status bar is visible.
@@ -2733,12 +2758,17 @@
                             mContentLeft, mContentTop, mContentRight, mContentBottom,
                             mCurLeft, mCurTop, mCurRight, mCurBottom));
                 }
-                if (mStatusBar.isVisibleLw() && !mStatusBar.isAnimatingLw()) {
+                if (mStatusBar.isVisibleLw() && !mStatusBar.isAnimatingLw() && !statusBarOverlay) {
                     // If the status bar is currently requested to be visible,
                     // and not in the process of animating on or off, then
                     // we can tell the app that it is covered by it.
                     mSystemTop = mUnrestrictedScreenTop + mStatusBarHeight;
                 }
+                if (mHideybars == HIDEYBARS_HIDING && !mStatusBar.isVisibleLw()) {
+                    // Hideybars have finished animating out, cleanup and reset alpha
+                    mHideybars = HIDEYBARS_NONE;
+                    updateSystemUiVisibilityLw();
+                }
             }
         }
     }
@@ -3276,7 +3306,8 @@
                     mDismissKeyguard = mWinDismissingKeyguard == win ?
                             DISMISS_KEYGUARD_CONTINUE : DISMISS_KEYGUARD_START;
                     mWinDismissingKeyguard = win;
-                    mForceStatusBarFromKeyguard = false;
+                    mForceStatusBarFromKeyguard =
+                            mShowingLockscreen && isKeyguardSecure();
                 }
                 if ((attrs.flags & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
                     mAllowLockscreenWhenOn = true;
@@ -3323,7 +3354,11 @@
                 // and mTopIsFullscreen is that that mTopIsFullscreen is set only if the window
                 // has the FLAG_FULLSCREEN set.  Not sure if there is another way that to be the
                 // case though.
-                if (topIsFullscreen) {
+                if (mHideybars == HIDEYBARS_SHOWING) {
+                    if (mStatusBar.showLw(true)) {
+                        changes |= FINISH_LAYOUT_REDO_LAYOUT;
+                    }
+                } else if (topIsFullscreen) {
                     if (DEBUG_LAYOUT) Log.v(TAG, "** HIDING status bar");
                     if (mStatusBar.hideLw(true)) {
                         changes |= FINISH_LAYOUT_REDO_LAYOUT;
@@ -4063,6 +4098,23 @@
         }
     };
 
+    private void receivedHideybars(String action) {
+        synchronized(mLock) {
+            if (action.equals(ACTION_HIDEYBARS)) {
+                if (mHideybars == HIDEYBARS_SHOWING) {
+                    if (DEBUG) Slog.d(TAG, "Not showing hideybars, already shown");
+                    return;
+                }
+                if (mStatusBar.isDisplayedLw()) {
+                    if (DEBUG) Slog.d(TAG, "Not showing hideybars, status bar already visible");
+                    return;
+                }
+                mHideybars = HIDEYBARS_SHOWING;
+                updateSystemUiVisibilityLw();
+            }
+        }
+    }
+
     @Override
     public void screenTurnedOff(int why) {
         EventLog.writeEvent(70000, 0);
@@ -4797,12 +4849,27 @@
             // will quickly lose focus once it correctly gets hidden.
             return 0;
         }
+
         int tmpVisibility = mFocusedWindow.getSystemUiVisibility()
                 & ~mResettingSystemUiFlags
                 & ~mForceClearedSystemUiFlags;
         if (mForcingShowNavBar && mFocusedWindow.getSurfaceLayer() < mForcingShowNavBarLayer) {
             tmpVisibility &= ~View.SYSTEM_UI_CLEARABLE_FLAGS;
         }
+
+        boolean hideybarsAllowed =
+                (mFocusedWindow.getAttrs().flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0
+                || mFocusedWindow.getAttrs().type == TYPE_STATUS_BAR;
+        if (mHideybars == HIDEYBARS_SHOWING) {
+            if (!hideybarsAllowed) {
+                mHideybars = HIDEYBARS_NONE;
+            } else {
+                tmpVisibility |= View.STATUS_BAR_OVERLAY;
+                if ((mLastSystemUiFlags & View.STATUS_BAR_OVERLAY) == 0) {
+                    mStatusBar.showLw(true);
+                }
+            }
+        }
         final int visibility = tmpVisibility;
         int diff = visibility ^ mLastSystemUiFlags;
         final boolean needsMenu = mFocusedWindow.getNeedsMenuLw(mTopFullscreenOpaqueWindowState);
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 1e1cf5a..b47e8a0 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -116,6 +116,8 @@
 
     private static final int MSG_LOCATION_CHANGED = 1;
 
+    private static final long NANOS_PER_MILLI = 1000000L;
+
     // Location Providers may sometimes deliver location updates
     // slightly faster that requested - provide grace period so
     // we don't unnecessarily filter events that are otherwise on
@@ -179,6 +181,11 @@
     // mapping from provider name to last known location
     private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
 
+    // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
+    // locations stored here are not fudged for coarse permissions.
+    private final HashMap<String, Location> mLastLocationCoarseInterval =
+            new HashMap<String, Location>();
+
     // all providers that operate over proxy, for authorizing incoming location
     private final ArrayList<LocationProviderProxy> mProxyProviders =
             new ArrayList<LocationProviderProxy>();
@@ -423,6 +430,7 @@
         mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
         synchronized (mLock) {
             mLastLocation.clear();
+            mLastLocationCoarseInterval.clear();
             for (LocationProviderInterface p : mProviders) {
                 updateProviderListenersLocked(p.getName(), false, mCurrentUserId);
             }
@@ -1407,7 +1415,14 @@
 
                 if (!isAllowedByUserSettingsLocked(name, uid)) return null;
 
-                Location location = mLastLocation.get(name);
+                Location location;
+                if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
+                    // Make sure that an app with coarse permissions can't get frequent location
+                    // updates by calling LocationManager.getLastKnownLocation repeatedly.
+                    location = mLastLocationCoarseInterval.get(name);
+                } else {
+                    location = mLastLocation.get(name);
+                }
                 if (location == null) {
                     return null;
                 }
@@ -1673,7 +1688,8 @@
 
         // Check whether sufficient time has passed
         long minTime = record.mRequest.getFastestInterval();
-        long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos()) / 1000000L;
+        long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
+                / NANOS_PER_MILLI;
         if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
             return false;
         }
@@ -1726,13 +1742,30 @@
         }
         lastLocation.set(location);
 
+        // Update last known coarse interval location if enough time has passed.
+        Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
+        if (lastLocationCoarseInterval == null) {
+            lastLocationCoarseInterval = new Location(location);
+            mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
+        }
+        long timeDiffNanos = location.getElapsedRealtimeNanos()
+                - lastLocationCoarseInterval.getElapsedRealtimeNanos();
+        if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
+            lastLocationCoarseInterval.set(location);
+        }
+        // Don't ever return a coarse location that is more recent than the allowed update
+        // interval (i.e. don't allow an app to keep registering and unregistering for
+        // location updates to overcome the minimum interval).
+        noGPSLocation =
+                lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
+
         // Skip if there are no UpdateRecords for this provider.
         ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
         if (records == null || records.size() == 0) return;
 
         // Fetch coarse location
         Location coarseLocation = null;
-        if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
+        if (noGPSLocation != null) {
             coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
         }
 
@@ -2021,6 +2054,7 @@
             addProviderLocked(provider);
             mMockProviders.put(name, provider);
             mLastLocation.put(name, null);
+            mLastLocationCoarseInterval.put(name, null);
             updateProvidersLocked();
         }
         Binder.restoreCallingIdentity(identity);
@@ -2043,6 +2077,7 @@
                 addProviderLocked(realProvider);
             }
             mLastLocation.put(provider, null);
+            mLastLocationCoarseInterval.put(provider, null);
             updateProvidersLocked();
             Binder.restoreCallingIdentity(identity);
         }
@@ -2174,6 +2209,13 @@
                 pw.println("    " + provider + ": " + location);
             }
 
+            pw.println("  Last Known Locations Coarse Intervals:");
+            for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
+                String provider = entry.getKey();
+                Location location = entry.getValue();
+                pw.println("    " + provider + ": " + location);
+            }
+
             mGeofenceManager.dump(pw);
 
             if (mEnabledProviders.size() > 0) {
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index d2acb40..0d266c2 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -990,7 +990,8 @@
                 mConnector.execute("softap", "set", wlanIface);
             } else {
                 mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
-                        getSecurityType(wifiConfig), wifiConfig.preSharedKey);
+                                   "broadcast", getSecurityType(wifiConfig),
+                                   wifiConfig.preSharedKey);
             }
             mConnector.execute("softap", "startap");
         } catch (NativeDaemonConnectorException e) {
@@ -1039,7 +1040,8 @@
                 mConnector.execute("softap", "set", wlanIface);
             } else {
                 mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
-                        getSecurityType(wifiConfig), wifiConfig.preSharedKey);
+                                   "broadcast", getSecurityType(wifiConfig),
+                                   wifiConfig.preSharedKey);
             }
         } catch (NativeDaemonConnectorException e) {
             throw e.rethrowAsParcelableException();
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index cfb892f..fa18e76 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -43,11 +43,13 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.database.ContentObserver;
+import android.graphics.Bitmap;
 import android.media.AudioManager;
 import android.media.IAudioService;
 import android.media.IRingtonePlayer;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
@@ -81,6 +83,7 @@
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.lang.reflect.Array;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -264,18 +267,32 @@
     }
 
     private static class Archive {
-        static final int BUFFER_SIZE = 1000;
+        static final int BUFFER_SIZE = 250;
         ArrayDeque<StatusBarNotification> mBuffer = new ArrayDeque<StatusBarNotification>(BUFFER_SIZE);
 
         public Archive() {
         }
 
+        public String toString() {
+            final StringBuilder sb = new StringBuilder();
+            final int N = mBuffer.size();
+            sb.append("Archive (");
+            sb.append(N);
+            sb.append(" notification");
+            sb.append((N==1)?")":"s)");
+            return sb.toString();
+        }
+
         public void record(StatusBarNotification nr) {
             // Nuke heavy parts of notification before storing in archive
             nr.notification.tickerView = null;
             nr.notification.contentView = null;
             nr.notification.bigContentView = null;
             nr.notification.largeIcon = null;
+            final Bundle extras = nr.notification.extras;
+            extras.remove(Notification.EXTRA_LARGE_ICON);
+            extras.remove(Notification.EXTRA_LARGE_ICON_BIG);
+            extras.remove(Notification.EXTRA_PICTURE);
 
             if (mBuffer.size() == BUFFER_SIZE) {
                 mBuffer.removeFirst();
@@ -283,6 +300,7 @@
             mBuffer.addLast(nr);
         }
 
+
         public void clear() {
             mBuffer.clear();
         }
@@ -815,22 +833,61 @@
         void dump(PrintWriter pw, String prefix, Context baseContext) {
             final Notification notification = sbn.notification;
             pw.println(prefix + this);
+            pw.println(prefix + "  uid=" + sbn.uid + " userId=" + sbn.getUserId());
             pw.println(prefix + "  icon=0x" + Integer.toHexString(notification.icon)
-                    + " / " + idDebugString(baseContext, this.sbn.pkg, notification.icon));
-            pw.println(prefix + "  pri=" + notification.priority);
-            pw.println(prefix + "  score=" + this.sbn.score);
+                    + " / " + idDebugString(baseContext, sbn.pkg, notification.icon));
+            pw.println(prefix + "  pri=" + notification.priority + " score=" + sbn.score);
             pw.println(prefix + "  contentIntent=" + notification.contentIntent);
             pw.println(prefix + "  deleteIntent=" + notification.deleteIntent);
             pw.println(prefix + "  tickerText=" + notification.tickerText);
             pw.println(prefix + "  contentView=" + notification.contentView);
-            pw.println(prefix + "  uid=" + this.sbn.uid + " userId=" + this.sbn.getUserId());
-            pw.println(prefix + "  defaults=0x" + Integer.toHexString(notification.defaults));
-            pw.println(prefix + "  flags=0x" + Integer.toHexString(notification.flags));
+            pw.println(prefix + String.format("  defaults=0x%08x flags=0x%08x",
+                    notification.defaults, notification.flags));
             pw.println(prefix + "  sound=" + notification.sound);
             pw.println(prefix + "  vibrate=" + Arrays.toString(notification.vibrate));
-            pw.println(prefix + "  ledARGB=0x" + Integer.toHexString(notification.ledARGB)
-                    + " ledOnMS=" + notification.ledOnMS
-                    + " ledOffMS=" + notification.ledOffMS);
+            pw.println(prefix + String.format("  led=0x%08x onMs=%d offMs=%d",
+                    notification.ledARGB, notification.ledOnMS, notification.ledOffMS));
+            if (notification.actions != null && notification.actions.length > 0) {
+                pw.println(prefix + "  actions={");
+                final int N = notification.actions.length;
+                for (int i=0; i<N; i++) {
+                    final Notification.Action action = notification.actions[i];
+                    pw.println(String.format("%s    [%d] \"%s\" -> %s",
+                            prefix,
+                            i,
+                            action.title,
+                            action.actionIntent.toString()
+                            ));
+                }
+                pw.println(prefix + "  }");
+            }
+            if (notification.extras != null && notification.extras.size() > 0) {
+                pw.println(prefix + "  extras={");
+                for (String key : notification.extras.keySet()) {
+                    pw.print(prefix + "    " + key + "=");
+                    Object val = notification.extras.get(key);
+                    if (val == null) {
+                        pw.println("null");
+                    } else {
+                        pw.print(val.toString());
+                        if (val instanceof Bitmap) {
+                            pw.print(String.format(" (%dx%d)",
+                                    ((Bitmap) val).getWidth(),
+                                    ((Bitmap) val).getHeight()));
+                        } else if (val.getClass().isArray()) {
+                            pw.println(" {");
+                            final int N = Array.getLength(val);
+                            for (int i=0; i<N; i++) {
+                                if (i > 0) pw.println(",");
+                                pw.print(prefix + "      " + Array.get(val, i));
+                            }
+                            pw.print("\n" + prefix + "    }");
+                        }
+                        pw.println();
+                    }
+                }
+                pw.println(prefix + "  }");
+            }
         }
 
         @Override
@@ -2081,7 +2138,7 @@
             if (N > 0) {
                 pw.println("  Lights List:");
                 for (int i=0; i<N; i++) {
-                    mLights.get(i).dump(pw, "    ", mContext);
+                    pw.println("    " + mLights.get(i));
                 }
                 pw.println("  ");
             }
@@ -2090,6 +2147,17 @@
             pw.println("  mVibrateNotification=" + mVibrateNotification);
             pw.println("  mDisabledNotifications=0x" + Integer.toHexString(mDisabledNotifications));
             pw.println("  mSystemReady=" + mSystemReady);
+            pw.println("  mArchive=" + mArchive.toString());
+            Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
+            int i=0;
+            while (iter.hasNext()) {
+                pw.println("    " + iter.next());
+                if (++i >= 5) {
+                    if (iter.hasNext()) pw.println("    ...");
+                    break;
+                }
+            }
+
         }
     }
 }
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 110c4da..1f3ac96 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -970,7 +970,7 @@
 
     private void addServiceLocked(Service service, UserState userState) {
         try {
-            service.linkToOwnDeath();
+            service.linkToOwnDeathLocked();
             userState.mBoundServices.add(service);
             userState.mComponentNameToServiceMap.put(service.mComponentName, service);
         } catch (RemoteException re) {
@@ -987,7 +987,7 @@
     private void removeServiceLocked(Service service, UserState userState) {
         userState.mBoundServices.remove(service);
         userState.mComponentNameToServiceMap.remove(service.mComponentName);
-        service.unlinkToOwnDeath();
+        service.unlinkToOwnDeathLocked();
     }
 
     /**
@@ -1765,7 +1765,7 @@
                 userState.destroyUiAutomationService();
             }
             removeServiceLocked(this, userState);
-            dispose();
+            resetLocked();
             return true;
         }
 
@@ -1817,11 +1817,13 @@
                 addServiceLocked(this, userState);
                 if (userState.mBindingServices.contains(mComponentName)) {
                     userState.mBindingServices.remove(mComponentName);
-                    onUserStateChangedLocked(userState);
                     try {
-                        mServiceInterface.setConnection(this, mId);
+                       mServiceInterface.setConnection(this, mId);
+                       onUserStateChangedLocked(userState);
                     } catch (RemoteException re) {
-                        Slog.w(LOG_TAG, "Error while setting connection for service: " + service, re);
+                        Slog.w(LOG_TAG, "Error while setting connection for service: "
+                                + service, re);
+                        binderDied();
                     }
                 } else {
                     binderDied();
@@ -2148,15 +2150,15 @@
             /* do nothing - #binderDied takes care */
         }
 
-        public void linkToOwnDeath() throws RemoteException {
+        public void linkToOwnDeathLocked() throws RemoteException {
             mService.linkToDeath(this, 0);
         }
 
-        public void unlinkToOwnDeath() {
+        public void unlinkToOwnDeathLocked() {
             mService.unlinkToDeath(this, 0);
         }
 
-        public void dispose() {
+        public void resetLocked() {
             try {
                 // Clear the proxy in the other process so this
                 // IAccessibilityServiceConnection can be garbage collected.
@@ -2168,13 +2170,24 @@
             mServiceInterface = null;
         }
 
+        public boolean isInitializedLocked() {
+            return (mService != null);
+        }
+
         public void binderDied() {
             synchronized (mLock) {
+                // It is possible that this service's package was force stopped during
+                // whose handling the death recipient is unlinked and still get a call
+                // on binderDied since the call was made before we unlink but was
+                // waiting on the lock we held during the force stop handling.
+                if (!isInitializedLocked()) {
+                    return;
+                }
                 mKeyEventDispatcher.flush();
                 UserState userState = getUserStateLocked(mUserId);
                 // The death recipient is unregistered in removeServiceLocked
                 removeServiceLocked(this, userState);
-                dispose();
+                resetLocked();
                 if (mIsAutomation) {
                     // We no longer have an automation service, so restore
                     // the state based on values in the settings database.
@@ -2499,7 +2512,9 @@
             public void flush() {
                 synchronized (mLock) {
                     cancelAllPendingEventsLocked();
-                    mSentEventsVerifier.reset();
+                    if (mSentEventsVerifier != null) {
+                        mSentEventsVerifier.reset();
+                    }
                 }
             }
 
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 16c7824..a3bb823 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -5024,6 +5024,10 @@
             return ActivityManagerService.this.checkComponentPermission(permission, pid, uid,
                     owningUid, exported);
         }
+
+        public Object getAMSLock() {
+            return ActivityManagerService.this;
+        }
     }
 
     /**
diff --git a/services/java/com/android/server/firewall/IntentFirewall.java b/services/java/com/android/server/firewall/IntentFirewall.java
index 08e6b45..edba243 100644
--- a/services/java/com/android/server/firewall/IntentFirewall.java
+++ b/services/java/com/android/server/firewall/IntentFirewall.java
@@ -25,6 +25,9 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.os.Environment;
+import android.os.FileObserver;
+import android.os.Handler;
+import android.os.Message;
 import android.os.RemoteException;
 import android.util.Slog;
 import android.util.Xml;
@@ -58,19 +61,18 @@
     private static final String TAG_BROADCAST = "broadcast";
 
     private static final int TYPE_ACTIVITY = 0;
-    private static final int TYPE_SERVICE = 1;
-    private static final int TYPE_BROADCAST = 2;
+    private static final int TYPE_BROADCAST = 1;
+    private static final int TYPE_SERVICE = 2;
 
     private static final HashMap<String, FilterFactory> factoryMap;
 
     private final AMSInterface mAms;
 
-    private final IntentResolver<FirewallIntentFilter, Rule> mActivityResolver =
-            new FirewallIntentResolver();
-    private final IntentResolver<FirewallIntentFilter, Rule> mServiceResolver =
-            new FirewallIntentResolver();
-    private final IntentResolver<FirewallIntentFilter, Rule> mBroadcastResolver =
-            new FirewallIntentResolver();
+    private final RuleObserver mObserver;
+
+    private FirewallIntentResolver mActivityResolver = new FirewallIntentResolver();
+    private FirewallIntentResolver mBroadcastResolver = new FirewallIntentResolver();
+    private FirewallIntentResolver mServiceResolver = new FirewallIntentResolver();
 
     static {
         FilterFactory[] factories = new FilterFactory[] {
@@ -104,9 +106,18 @@
 
     public IntentFirewall(AMSInterface ams) {
         mAms = ams;
-        readRules(getRulesFile());
+        File rulesFile = getRulesFile();
+
+        readRules(rulesFile);
+
+        mObserver = new RuleObserver(rulesFile);
+        mObserver.startWatching();
     }
 
+    /**
+     * This is called from ActivityManager to check if a start activity intent should be allowed.
+     * It is assumed the caller is already holding the global ActivityManagerService lock.
+     */
     public boolean checkStartActivity(Intent intent, ApplicationInfo callerApp, int callerUid,
             int callerPid, String resolvedType, ActivityInfo resolvedActivity) {
         List<Rule> matchingRules = mActivityResolver.queryIntent(intent, resolvedType, false, 0);
@@ -208,7 +219,18 @@
         return RULES_FILE;
     }
 
+    /**
+     * Reads rules from the given file and replaces our set of rules with the newly read rules
+     *
+     * All calls to this method from the file observer come through a handler and are inherently
+     * serialized
+     */
     private void readRules(File rulesFile) {
+        FirewallIntentResolver[] resolvers = new FirewallIntentResolver[3];
+        for (int i=0; i<resolvers.length; i++) {
+            resolvers[i] = new FirewallIntentResolver();
+        }
+
         FileInputStream fis;
         try {
             fis = new FileInputStream(rulesFile);
@@ -224,40 +246,59 @@
 
             XmlUtils.beginDocument(parser, TAG_RULES);
 
+            int[] numRules = new int[3];
+
             int outerDepth = parser.getDepth();
             while (XmlUtils.nextElementWithin(parser, outerDepth)) {
-                IntentResolver<FirewallIntentFilter, Rule> resolver = null;
+                int ruleType = -1;
+
                 String tagName = parser.getName();
                 if (tagName.equals(TAG_ACTIVITY)) {
-                    resolver = mActivityResolver;
-                } else if (tagName.equals(TAG_SERVICE)) {
-                    resolver = mServiceResolver;
+                    ruleType = TYPE_ACTIVITY;
                 } else if (tagName.equals(TAG_BROADCAST)) {
-                    resolver = mBroadcastResolver;
+                    ruleType = TYPE_BROADCAST;
+                } else if (tagName.equals(TAG_SERVICE)) {
+                    ruleType = TYPE_SERVICE;
                 }
 
-                if (resolver != null) {
+                if (ruleType != -1) {
                     Rule rule = new Rule();
 
+                    FirewallIntentResolver resolver = resolvers[ruleType];
+
+                    // if we get an error while parsing a particular rule, we'll just ignore
+                    // that rule and continue on with the next rule
                     try {
                         rule.readFromXml(parser);
                     } catch (XmlPullParserException ex) {
                         Slog.e(TAG, "Error reading intent firewall rule", ex);
                         continue;
-                    } catch (IOException ex) {
-                        Slog.e(TAG, "Error reading intent firewall rule", ex);
-                        continue;
                     }
 
+                    numRules[ruleType]++;
+
                     for (int i=0; i<rule.getIntentFilterCount(); i++) {
                         resolver.addFilter(rule.getIntentFilter(i));
                     }
                 }
             }
+
+            Slog.i(TAG, "Read new rules (A:" + numRules[TYPE_ACTIVITY] +
+                    " B:" + numRules[TYPE_BROADCAST] + " S:" + numRules[TYPE_SERVICE] + ")");
+
+            synchronized (mAms.getAMSLock()) {
+                mActivityResolver = resolvers[TYPE_ACTIVITY];
+                mBroadcastResolver = resolvers[TYPE_BROADCAST];
+                mServiceResolver = resolvers[TYPE_SERVICE];
+            }
         } catch (XmlPullParserException ex) {
+            // if there was an error outside of a specific rule, then there are probably
+            // structural problems with the xml file, and we should completely ignore it
             Slog.e(TAG, "Error reading intent firewall rules", ex);
+            clearRules();
         } catch (IOException ex) {
             Slog.e(TAG, "Error reading intent firewall rules", ex);
+            clearRules();
         } finally {
             try {
                 fis.close();
@@ -267,6 +308,22 @@
         }
     }
 
+    /**
+     * Clears out all of our rules
+     *
+     * All calls to this method from the file observer come through a handler and are inherently
+     * serialized
+     */
+    private void clearRules() {
+        Slog.i(TAG, "Clearing all rules");
+
+        synchronized (mAms.getAMSLock())  {
+            mActivityResolver = new FirewallIntentResolver();
+            mBroadcastResolver = new FirewallIntentResolver();
+            mServiceResolver = new FirewallIntentResolver();
+        }
+    }
+
     static Filter parseFilter(XmlPullParser parser) throws IOException, XmlPullParserException {
         String elementName = parser.getName();
 
@@ -363,6 +420,58 @@
         }
     }
 
+    private static final int READ_RULES = 0;
+    private static final int CLEAR_RULES = 1;
+
+    final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case READ_RULES:
+                    readRules(getRulesFile());
+                    break;
+                case CLEAR_RULES:
+                    clearRules();
+                    break;
+            }
+        }
+    };
+
+    /**
+     * Monitors for the creation/deletion/modification of the rule file
+     */
+    private class RuleObserver extends FileObserver {
+        // The file name we're monitoring, with no path component
+        private final String mMonitoredFile;
+
+        private static final int CREATED_FLAGS = FileObserver.CREATE|FileObserver.MOVED_TO|
+                FileObserver.CLOSE_WRITE;
+        private static final int DELETED_FLAGS = FileObserver.DELETE|FileObserver.MOVED_FROM;
+
+        public RuleObserver(File monitoredFile) {
+            super(monitoredFile.getParentFile().getAbsolutePath(), CREATED_FLAGS|DELETED_FLAGS);
+            mMonitoredFile = monitoredFile.getName();
+        }
+
+        @Override
+        public void onEvent(int event, String path) {
+            if (path.equals(mMonitoredFile)) {
+                // we wait 250ms before taking any action on an event, in order to dedup multiple
+                // events. E.g. a delete event followed by a create event followed by a subsequent
+                // write+close event;
+                if ((event & CREATED_FLAGS) != 0) {
+                    mHandler.removeMessages(READ_RULES);
+                    mHandler.removeMessages(CLEAR_RULES);
+                    mHandler.sendEmptyMessageDelayed(READ_RULES, 250);
+                } else if ((event & DELETED_FLAGS) != 0) {
+                    mHandler.removeMessages(READ_RULES);
+                    mHandler.removeMessages(CLEAR_RULES);
+                    mHandler.sendEmptyMessageDelayed(CLEAR_RULES, 250);
+                }
+            }
+        }
+    }
+
     /**
      * This interface contains the methods we need from ActivityManagerService. This allows AMS to
      * export these methods to us without making them public, and also makes it easier to test this
@@ -371,6 +480,7 @@
     public interface AMSInterface {
         int checkComponentPermission(String permission, int pid, int uid,
                 int owningUid, boolean exported);
+        Object getAMSLock();
     }
 
     /**
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index 1ebff67..8c88cab 100644
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -36,6 +36,7 @@
 import android.location.LocationListener;
 import android.location.LocationManager;
 import android.location.LocationProvider;
+import android.location.LocationRequest;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.net.Uri;
@@ -262,6 +263,9 @@
     // true if we started navigation
     private boolean mStarted;
 
+    // true if single shot request is in progress
+    private boolean mSingleShot;
+
     // capabilities of the GPS engine
     private int mEngineCapabilities;
 
@@ -382,7 +386,7 @@
 
             if (action.equals(ALARM_WAKEUP)) {
                 if (DEBUG) Log.d(TAG, "ALARM_WAKEUP");
-                startNavigating();
+                startNavigating(false);
             } else if (action.equals(ALARM_TIMEOUT)) {
                 if (DEBUG) Log.d(TAG, "ALARM_TIMEOUT");
                 hibernate();
@@ -803,10 +807,22 @@
     }
 
     private void handleSetRequest(ProviderRequest request, WorkSource source) {
+        boolean singleShot = false;
+
+        // see if the request is for a single update
+        if (request.locationRequests != null && request.locationRequests.size() > 0) {
+            // if any request has zero or more than one updates
+            // requested, then this is not single-shot mode
+            singleShot = true;
+
+            for (LocationRequest lr : request.locationRequests) {
+                if (lr.getNumUpdates() != 1) {
+                    singleShot = false;
+                }
+            }
+        }
+
         if (DEBUG) Log.d(TAG, "setRequest " + request);
-
-
-
         if (request.reportLocation) {
             // update client uids
             updateClientUids(source);
@@ -828,7 +844,7 @@
                 }
             } else if (!mStarted) {
                 // start GPS
-                startNavigating();
+                startNavigating(singleShot);
             }
         } else {
             updateClientUids(new WorkSource());
@@ -982,21 +998,44 @@
         return false;
     }
 
-    private void startNavigating() {
+    private void startNavigating(boolean singleShot) {
         if (!mStarted) {
-            if (DEBUG) Log.d(TAG, "startNavigating");
+            if (DEBUG) Log.d(TAG, "startNavigating, singleShot is " + singleShot);
             mTimeToFirstFix = 0;
             mLastFixTime = 0;
             mStarted = true;
+            mSingleShot = singleShot;
             mPositionMode = GPS_POSITION_MODE_STANDALONE;
 
              if (Settings.Global.getInt(mContext.getContentResolver(),
                     Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0) {
-                if (hasCapability(GPS_CAPABILITY_MSB)) {
+                if (singleShot && hasCapability(GPS_CAPABILITY_MSA)) {
+                    mPositionMode = GPS_POSITION_MODE_MS_ASSISTED;
+                } else if (hasCapability(GPS_CAPABILITY_MSB)) {
                     mPositionMode = GPS_POSITION_MODE_MS_BASED;
                 }
             }
 
+            if (DEBUG) {
+                String mode;
+
+                switch(mPositionMode) {
+                    case GPS_POSITION_MODE_STANDALONE:
+                        mode = "standalone";
+                        break;
+                    case GPS_POSITION_MODE_MS_ASSISTED:
+                        mode = "MS_ASSISTED";
+                        break;
+                    case GPS_POSITION_MODE_MS_BASED:
+                        mode = "MS_BASED";
+                        break;
+                    default:
+                        mode = "unknown";
+                        break;
+                }
+                Log.d(TAG, "setting position_mode to " + mode);
+            }
+
             int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
             if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
                     interval, 0, 0)) {
@@ -1028,6 +1067,7 @@
         if (DEBUG) Log.d(TAG, "stopNavigating");
         if (mStarted) {
             mStarted = false;
+            mSingleShot = false;
             native_stop();
             mTimeToFirstFix = 0;
             mLastFixTime = 0;
@@ -1122,6 +1162,10 @@
             }
         }
 
+        if (mSingleShot) {
+            stopNavigating();
+        }
+
         if (mStarted && mStatus != LocationProvider.AVAILABLE) {
             // we want to time out if we do not receive a fix
             // within the time out and we are requesting infrequent fixes
@@ -1283,7 +1327,8 @@
                     if (DEBUG) Log.d(TAG, "PhoneConstants.APN_REQUEST_STARTED");
                     // Nothing to do here
                 } else {
-                    if (DEBUG) Log.d(TAG, "startUsingNetworkFeature failed");
+                    if (DEBUG) Log.d(TAG, "startUsingNetworkFeature failed, value is " +
+                                     result);
                     mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
                     native_agps_data_conn_failed();
                 }
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index d4c727b..905f55d 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -19,6 +19,7 @@
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
 import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD;
@@ -948,6 +949,7 @@
         return mContentChanged && !mExiting && !mWinAnimator.mLastHidden && mService.okToDisplay()
                 && (mFrame.top != mLastFrame.top
                         || mFrame.left != mLastFrame.left)
+                && (mAttrs.privateFlags&PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
                 && (mAttachedWindow == null || !mAttachedWindow.shouldAnimateMove());
     }
 
diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java
index d3d5b1b..23a4e71 100644
--- a/wifi/java/android/net/wifi/WifiConfigStore.java
+++ b/wifi/java/android/net/wifi/WifiConfigStore.java
@@ -1111,7 +1111,8 @@
                 break setVariables;
             }
 
-            if (config.enterpriseConfig != null) {
+            if (config.enterpriseConfig != null &&
+                    config.enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE) {
 
                 WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig;
 
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index a5d98cc..2c3df95 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -2383,6 +2383,8 @@
                 mWifiNative.disconnect();
                 transitionTo(mScanModeState);
             } else {
+                /* Driver stop may have disabled networks, enable right after start */
+                mWifiConfigStore.enableAllNetworks();
                 mWifiNative.reconnect();
                 // Status pulls in the current supplicant state and network connection state
                 // events over the monitor connection. This helps framework sync up with