Merge "Fix API name" into jb-mr2-dev
diff --git a/Android.mk b/Android.mk
index 8115472..bd88877 100644
--- a/Android.mk
+++ b/Android.mk
@@ -126,6 +126,7 @@
 	core/java/android/hardware/input/IInputDevicesChangedListener.aidl \
 	core/java/android/hardware/location/IGeofenceHardware.aidl \
 	core/java/android/hardware/location/IGeofenceHardwareCallback.aidl \
+	core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl \
 	core/java/android/hardware/usb/IUsbManager.aidl \
 	core/java/android/net/IConnectivityManager.aidl \
 	core/java/android/net/INetworkManagementEventObserver.aidl \
diff --git a/api/current.txt b/api/current.txt
index aba9793..2ec1533 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -37,8 +37,6 @@
     field public static final java.lang.String CALL_PHONE = "android.permission.CALL_PHONE";
     field public static final java.lang.String CALL_PRIVILEGED = "android.permission.CALL_PRIVILEGED";
     field public static final java.lang.String CAMERA = "android.permission.CAMERA";
-    field public static final java.lang.String CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = "android.permission.CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
-    field public static final java.lang.String CAN_REQUEST_TOUCH_EXPLORATION_MODE = "android.permission.CAN_REQUEST_TOUCH_EXPLORATION_MODE";
     field public static final java.lang.String CHANGE_COMPONENT_ENABLED_STATE = "android.permission.CHANGE_COMPONENT_ENABLED_STATE";
     field public static final java.lang.String CHANGE_CONFIGURATION = "android.permission.CHANGE_CONFIGURATION";
     field public static final java.lang.String CHANGE_NETWORK_STATE = "android.permission.CHANGE_NETWORK_STATE";
@@ -322,6 +320,9 @@
     field public static final int cacheColorHint = 16843009; // 0x1010101
     field public static final int calendarViewShown = 16843596; // 0x101034c
     field public static final int calendarViewStyle = 16843613; // 0x101035d
+    field public static final int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
+    field public static final int canRequestFilterKeyEvents = 16843737; // 0x10103d9
+    field public static final int canRequestTouchExplorationMode = 16843735; // 0x10103d7
     field public static final int canRetrieveWindowContent = 16843653; // 0x1010385
     field public static final int candidatesTextStyleSpans = 16843312; // 0x1010230
     field public static final deprecated int capitalize = 16843113; // 0x1010169
@@ -1703,7 +1704,6 @@
     field public static final int Theme_Black = 16973832; // 0x1030008
     field public static final int Theme_Black_NoTitleBar = 16973833; // 0x1030009
     field public static final int Theme_Black_NoTitleBar_Fullscreen = 16973834; // 0x103000a
-    field public static final int Theme_Black_NoTitleBar_Overscan = 16974303; // 0x10301df
     field public static final int Theme_DeviceDefault = 16974120; // 0x1030128
     field public static final int Theme_DeviceDefault_Dialog = 16974126; // 0x103012e
     field public static final int Theme_DeviceDefault_DialogWhenLarge = 16974134; // 0x1030136
@@ -1722,11 +1722,11 @@
     field public static final int Theme_DeviceDefault_Light_Dialog_NoActionBar_MinWidth = 16974133; // 0x1030135
     field public static final int Theme_DeviceDefault_Light_NoActionBar = 16974124; // 0x103012c
     field public static final int Theme_DeviceDefault_Light_NoActionBar_Fullscreen = 16974125; // 0x103012d
-    field public static final int Theme_DeviceDefault_Light_NoActionBar_Overscan = 16974307; // 0x10301e3
+    field public static final int Theme_DeviceDefault_Light_NoActionBar_Overscan = 16974304; // 0x10301e0
     field public static final int Theme_DeviceDefault_Light_Panel = 16974139; // 0x103013b
     field public static final int Theme_DeviceDefault_NoActionBar = 16974121; // 0x1030129
     field public static final int Theme_DeviceDefault_NoActionBar_Fullscreen = 16974122; // 0x103012a
-    field public static final int Theme_DeviceDefault_NoActionBar_Overscan = 16974306; // 0x10301e2
+    field public static final int Theme_DeviceDefault_NoActionBar_Overscan = 16974303; // 0x10301df
     field public static final int Theme_DeviceDefault_Panel = 16974138; // 0x103013a
     field public static final int Theme_DeviceDefault_Wallpaper = 16974140; // 0x103013c
     field public static final int Theme_DeviceDefault_Wallpaper_NoTitleBar = 16974141; // 0x103013d
@@ -1749,11 +1749,11 @@
     field public static final int Theme_Holo_Light_Dialog_NoActionBar_MinWidth = 16973942; // 0x1030076
     field public static final int Theme_Holo_Light_NoActionBar = 16974064; // 0x10300f0
     field public static final int Theme_Holo_Light_NoActionBar_Fullscreen = 16974065; // 0x10300f1
-    field public static final int Theme_Holo_Light_NoActionBar_Overscan = 16974305; // 0x10301e1
+    field public static final int Theme_Holo_Light_NoActionBar_Overscan = 16974302; // 0x10301de
     field public static final int Theme_Holo_Light_Panel = 16973948; // 0x103007c
     field public static final int Theme_Holo_NoActionBar = 16973932; // 0x103006c
     field public static final int Theme_Holo_NoActionBar_Fullscreen = 16973933; // 0x103006d
-    field public static final int Theme_Holo_NoActionBar_Overscan = 16974304; // 0x10301e0
+    field public static final int Theme_Holo_NoActionBar_Overscan = 16974301; // 0x10301dd
     field public static final int Theme_Holo_Panel = 16973947; // 0x103007b
     field public static final int Theme_Holo_Wallpaper = 16973949; // 0x103007d
     field public static final int Theme_Holo_Wallpaper_NoTitleBar = 16973950; // 0x103007e
@@ -1761,14 +1761,12 @@
     field public static final int Theme_Light = 16973836; // 0x103000c
     field public static final int Theme_Light_NoTitleBar = 16973837; // 0x103000d
     field public static final int Theme_Light_NoTitleBar_Fullscreen = 16973838; // 0x103000e
-    field public static final int Theme_Light_NoTitleBar_Overscan = 16974302; // 0x10301de
     field public static final int Theme_Light_Panel = 16973914; // 0x103005a
     field public static final int Theme_Light_WallpaperSettings = 16973922; // 0x1030062
     field public static final int Theme_NoDisplay = 16973909; // 0x1030055
     field public static final int Theme_NoTitleBar = 16973830; // 0x1030006
     field public static final int Theme_NoTitleBar_Fullscreen = 16973831; // 0x1030007
     field public static final int Theme_NoTitleBar_OverlayActionModes = 16973930; // 0x103006a
-    field public static final int Theme_NoTitleBar_Overscan = 16974301; // 0x10301dd
     field public static final int Theme_Panel = 16973913; // 0x1030059
     field public static final int Theme_Translucent = 16973839; // 0x103000f
     field public static final int Theme_Translucent_NoTitleBar = 16973840; // 0x1030010
@@ -2107,16 +2105,22 @@
 
   public class AccessibilityServiceInfo implements android.os.Parcelable {
     ctor public AccessibilityServiceInfo();
+    method public static java.lang.String capabilityToString(int);
     method public int describeContents();
     method public static java.lang.String feedbackTypeToString(int);
     method public static java.lang.String flagToString(int);
-    method public boolean getCanRetrieveWindowContent();
+    method public deprecated boolean getCanRetrieveWindowContent();
+    method public int getCapabilities();
     method public deprecated java.lang.String getDescription();
     method public java.lang.String getId();
     method public android.content.pm.ResolveInfo getResolveInfo();
     method public java.lang.String getSettingsActivityName();
     method public java.lang.String loadDescription(android.content.pm.PackageManager);
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
+    field public static final int CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 8; // 0x8
+    field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2
+    field public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 1; // 0x1
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final int DEFAULT = 1; // 0x1
     field public static final int FEEDBACK_ALL_MASK = -1; // 0xffffffff
@@ -2129,6 +2133,7 @@
     field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
     field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
     field public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
+    field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
     field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
     field public int eventTypes;
     field public int feedbackType;
@@ -2306,28 +2311,23 @@
 
 package android.animation {
 
-  public abstract interface Animatable {
-    method public abstract long getDuration();
-    method public abstract android.animation.TimeInterpolator getInterpolator();
-    method public abstract long getStartDelay();
-    method public abstract android.animation.Animatable setDuration(long);
-    method public abstract void setInterpolator(android.animation.TimeInterpolator);
-    method public abstract void setStartDelay(long);
-  }
-
-  public abstract class Animator implements android.animation.Animatable java.lang.Cloneable {
+  public abstract class Animator implements java.lang.Cloneable {
     ctor public Animator();
     method public void addListener(android.animation.Animator.AnimatorListener);
     method public void cancel();
     method public android.animation.Animator clone();
     method public void end();
+    method public abstract long getDuration();
     method public android.animation.TimeInterpolator getInterpolator();
     method public java.util.ArrayList<android.animation.Animator.AnimatorListener> getListeners();
+    method public abstract long getStartDelay();
     method public abstract boolean isRunning();
     method public boolean isStarted();
     method public void removeAllListeners();
     method public void removeListener(android.animation.Animator.AnimatorListener);
     method public abstract android.animation.Animator setDuration(long);
+    method public abstract void setInterpolator(android.animation.TimeInterpolator);
+    method public abstract void setStartDelay(long);
     method public void setTarget(java.lang.Object);
     method public void setupEndValues();
     method public void setupStartValues();
@@ -3122,9 +3122,9 @@
     method public void onTerminate();
     method public void onTrimMemory(int);
     method public void registerActivityLifecycleCallbacks(android.app.Application.ActivityLifecycleCallbacks);
-    method public void registerOnProvideAssistData(android.app.Application.OnProvideAssistData);
+    method public void registerOnProvideAssistDataListener(android.app.Application.OnProvideAssistDataListener);
     method public void unregisterActivityLifecycleCallbacks(android.app.Application.ActivityLifecycleCallbacks);
-    method public void unregisterOnProvideAssistData(android.app.Application.OnProvideAssistData);
+    method public void unregisterOnProvideAssistDataListener(android.app.Application.OnProvideAssistDataListener);
   }
 
   public static abstract interface Application.ActivityLifecycleCallbacks {
@@ -3137,7 +3137,7 @@
     method public abstract void onActivityStopped(android.app.Activity);
   }
 
-  public static abstract interface Application.OnProvideAssistData {
+  public static abstract interface Application.OnProvideAssistDataListener {
     method public abstract void onProvideAssistData(android.app.Activity, android.os.Bundle);
   }
 
@@ -4633,13 +4633,11 @@
     method public boolean isEnabled();
     method public android.bluetooth.BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(java.lang.String, java.util.UUID) throws java.io.IOException;
     method public android.bluetooth.BluetoothServerSocket listenUsingRfcommWithServiceRecord(java.lang.String, java.util.UUID) throws java.io.IOException;
-    method public boolean registerCallback(android.bluetooth.BluetoothAdapterCallback);
     method public boolean setName(java.lang.String);
     method public boolean startDiscovery();
-    method public boolean startLeScan();
-    method public boolean startLeScan(java.util.UUID[]);
-    method public void stopLeScan();
-    method public boolean unRegisterCallback(android.bluetooth.BluetoothAdapterCallback);
+    method public boolean startLeScan(android.bluetooth.BluetoothAdapter.LeScanCallback);
+    method public boolean startLeScan(java.util.UUID[], android.bluetooth.BluetoothAdapter.LeScanCallback);
+    method public void stopLeScan(android.bluetooth.BluetoothAdapter.LeScanCallback);
     field public static final java.lang.String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED";
     field public static final java.lang.String ACTION_DISCOVERY_FINISHED = "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
     field public static final java.lang.String ACTION_DISCOVERY_STARTED = "android.bluetooth.adapter.action.DISCOVERY_STARTED";
@@ -4670,12 +4668,8 @@
     field public static final int STATE_TURNING_ON = 11; // 0xb
   }
 
-  public abstract class BluetoothAdapterCallback {
-    ctor public BluetoothAdapterCallback();
-    method public void onCallbackRegistration(int);
-    method public void onLeScan(android.bluetooth.BluetoothDevice, int, byte[]);
-    field public static final int CALLBACK_REGISTERED = 0; // 0x0
-    field public static final int CALLBACK_REGISTRATION_FAILURE = 1; // 0x1
+  public static abstract interface BluetoothAdapter.LeScanCallback {
+    method public abstract void onLeScan(android.bluetooth.BluetoothDevice, int, byte[]);
   }
 
   public class BluetoothAssignedNumbers {
@@ -5618,7 +5612,6 @@
     method public abstract java.lang.String[] fileList();
     method public abstract android.content.Context getApplicationContext();
     method public abstract android.content.pm.ApplicationInfo getApplicationInfo();
-    method public java.util.List<android.content.RestrictionEntry> getApplicationRestrictions();
     method public abstract android.content.res.AssetManager getAssets();
     method public abstract java.io.File getCacheDir();
     method public abstract java.lang.ClassLoader getClassLoader();
@@ -6205,8 +6198,9 @@
     field public static final java.lang.String EXTRA_REFERRER = "android.intent.extra.REFERRER";
     field public static final java.lang.String EXTRA_REMOTE_INTENT_TOKEN = "android.intent.extra.remote_intent_token";
     field public static final java.lang.String EXTRA_REPLACING = "android.intent.extra.REPLACING";
-    field public static final java.lang.String EXTRA_RESTRICTIONS = "android.intent.extra.restrictions";
+    field public static final java.lang.String EXTRA_RESTRICTIONS_BUNDLE = "android.intent.extra.restrictions_bundle";
     field public static final java.lang.String EXTRA_RESTRICTIONS_INTENT = "android.intent.extra.restrictions_intent";
+    field public static final java.lang.String EXTRA_RESTRICTIONS_LIST = "android.intent.extra.restrictions_list";
     field public static final java.lang.String EXTRA_RETURN_RESULT = "android.intent.extra.RETURN_RESULT";
     field public static final java.lang.String EXTRA_SHORTCUT_ICON = "android.intent.extra.shortcut.ICON";
     field public static final java.lang.String EXTRA_SHORTCUT_ICON_RESOURCE = "android.intent.extra.shortcut.ICON_RESOURCE";
@@ -10476,13 +10470,14 @@
 package android.hardware.location {
 
   public final class GeofenceHardware {
-    method public boolean addCircularFence(int, double, double, double, int, int, int, int, int, android.hardware.location.GeofenceHardwareCallback);
-    method public int[] getMonitoringTypesAndStatus();
+    method public boolean addGeofence(int, int, android.hardware.location.GeofenceHardwareRequest, android.hardware.location.GeofenceHardwareCallback);
+    method public int[] getMonitoringTypes();
+    method public int getStatusOfMonitoringType(int);
     method public boolean pauseGeofence(int, int);
-    method public boolean registerForMonitorStateChangeCallback(int, android.hardware.location.GeofenceHardwareCallback);
+    method public boolean registerForMonitorStateChangeCallback(int, android.hardware.location.GeofenceHardwareMonitorCallback);
     method public boolean removeGeofence(int, int);
     method public boolean resumeGeofence(int, int, int);
-    method public boolean unregisterForMonitorStateChangeCallback(int, android.hardware.location.GeofenceHardwareCallback);
+    method public boolean unregisterForMonitorStateChangeCallback(int, android.hardware.location.GeofenceHardwareMonitorCallback);
     field public static final int GEOFENCE_ENTERED = 1; // 0x1
     field public static final int GEOFENCE_ERROR_ID_EXISTS = 2; // 0x2
     field public static final int GEOFENCE_ERROR_ID_UNKNOWN = 3; // 0x3
@@ -10501,13 +10496,33 @@
   public abstract class GeofenceHardwareCallback {
     ctor public GeofenceHardwareCallback();
     method public void onGeofenceAdd(int, int);
-    method public void onGeofenceChange(int, int, android.location.Location, long, int);
     method public void onGeofencePause(int, int);
     method public void onGeofenceRemove(int, int);
     method public void onGeofenceResume(int, int);
+    method public void onGeofenceTransition(int, int, android.location.Location, long, int);
+  }
+
+  public abstract class GeofenceHardwareMonitorCallback {
+    ctor public GeofenceHardwareMonitorCallback();
     method public void onMonitoringSystemChange(int, boolean, android.location.Location);
   }
 
+  public final class GeofenceHardwareRequest {
+    ctor public GeofenceHardwareRequest();
+    method public static android.hardware.location.GeofenceHardwareRequest createCircularGeofence(double, double, double);
+    method public int getLastTransition();
+    method public double getLatitude();
+    method public double getLongitude();
+    method public int getMonitorTransitions();
+    method public int getNotificationResponsiveness();
+    method public double getRadius();
+    method public int getUnknownTimer();
+    method public void setLastTransition(int);
+    method public void setMonitorTransitions(int);
+    method public void setNotificationResponsiveness(int);
+    method public void setUnknownTimer(int);
+  }
+
 }
 
 package android.hardware.usb {
@@ -10579,11 +10594,11 @@
   }
 
   public class UsbDeviceConnection {
-    method public deprecated int bulkTransfer(android.hardware.usb.UsbEndpoint, byte[], int, int);
+    method public int bulkTransfer(android.hardware.usb.UsbEndpoint, byte[], int, int);
     method public int bulkTransfer(android.hardware.usb.UsbEndpoint, byte[], int, int, int);
     method public boolean claimInterface(android.hardware.usb.UsbInterface, boolean);
     method public void close();
-    method public deprecated int controlTransfer(int, int, int, int, byte[], int, int);
+    method public int controlTransfer(int, int, int, int, byte[], int, int);
     method public int controlTransfer(int, int, int, int, byte[], int, int, int);
     method public int getFileDescriptor();
     method public byte[] getRawDescriptors();
@@ -11801,6 +11816,66 @@
     ctor public MediaCryptoException(java.lang.String);
   }
 
+  public final class MediaDrm {
+    ctor public MediaDrm(java.util.UUID) throws android.media.MediaDrmException;
+    method public void closeSession(byte[]);
+    method public android.media.MediaDrm.CryptoSession getCryptoSession(byte[], java.lang.String, java.lang.String);
+    method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.HashMap<java.lang.String, java.lang.String>);
+    method public byte[] getPropertyByteArray(java.lang.String);
+    method public java.lang.String getPropertyString(java.lang.String);
+    method public android.media.MediaDrm.ProvisionRequest getProvisionRequest();
+    method public java.util.List<byte[]> getSecureStops();
+    method public static final boolean isCryptoSchemeSupported(java.util.UUID);
+    method public byte[] openSession();
+    method public byte[] provideKeyResponse(byte[], byte[]);
+    method public void provideProvisionResponse(byte[]);
+    method public java.util.HashMap<java.lang.String, java.lang.String> queryKeyStatus(byte[]);
+    method public final void release();
+    method public void releaseSecureStops(byte[]);
+    method public void removeKeys(byte[]);
+    method public void restoreKeys(byte[], byte[]);
+    method public void setOnEventListener(android.media.MediaDrm.OnEventListener);
+    method public void setPropertyByteArray(java.lang.String, byte[]);
+    method public void setPropertyString(java.lang.String, java.lang.String);
+    field public static final int EVENT_KEY_EXPIRED = 3; // 0x3
+    field public static final int EVENT_KEY_REQUIRED = 2; // 0x2
+    field public static final int EVENT_PROVISION_REQUIRED = 1; // 0x1
+    field public static final int EVENT_VENDOR_DEFINED = 4; // 0x4
+    field public static final int KEY_TYPE_OFFLINE = 2; // 0x2
+    field public static final int KEY_TYPE_RELEASE = 3; // 0x3
+    field public static final int KEY_TYPE_STREAMING = 1; // 0x1
+    field public static final java.lang.String PROPERTY_ALGORITHM = "algorithm";
+    field public static final java.lang.String PROPERTY_DESCRIPTION = "description";
+    field public static final java.lang.String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId";
+    field public static final java.lang.String PROPERTY_VENDOR = "vendor";
+    field public static final java.lang.String PROPERTY_VERSION = "version";
+  }
+
+  public final class MediaDrm.CryptoSession {
+    method public byte[] decrypt(byte[], byte[], byte[]);
+    method public byte[] encrypt(byte[], byte[], byte[]);
+    method public byte[] sign(byte[], byte[]);
+    method public boolean verify(byte[], byte[], byte[]);
+  }
+
+  public static final class MediaDrm.KeyRequest {
+    method public byte[] getData();
+    method public java.lang.String getDefaultUrl();
+  }
+
+  public static abstract interface MediaDrm.OnEventListener {
+    method public abstract void onEvent(android.media.MediaDrm, byte[], int, int, byte[]);
+  }
+
+  public static final class MediaDrm.ProvisionRequest {
+    method public byte[] getData();
+    method public java.lang.String getDefaultUrl();
+  }
+
+  public final class MediaDrmException extends java.lang.Exception {
+    ctor public MediaDrmException(java.lang.String);
+  }
+
   public final class MediaExtractor {
     ctor public MediaExtractor();
     method public boolean advance();
@@ -12267,13 +12342,17 @@
     ctor public RemoteControlClient(android.app.PendingIntent);
     ctor public RemoteControlClient(android.app.PendingIntent, android.os.Looper);
     method public android.media.RemoteControlClient.MetadataEditor editMetadata(boolean);
+    method public void setOnGetPlaybackPositionListener(android.media.RemoteControlClient.OnGetPlaybackPositionListener);
+    method public void setPlaybackPositionUpdateListener(android.media.RemoteControlClient.OnPlaybackPositionUpdateListener);
     method public void setPlaybackState(int);
+    method public void setPlaybackState(int, long, float);
     method public void setTransportControlFlags(int);
     field public static final int FLAG_KEY_MEDIA_FAST_FORWARD = 64; // 0x40
     field public static final int FLAG_KEY_MEDIA_NEXT = 128; // 0x80
     field public static final int FLAG_KEY_MEDIA_PAUSE = 16; // 0x10
     field public static final int FLAG_KEY_MEDIA_PLAY = 4; // 0x4
     field public static final int FLAG_KEY_MEDIA_PLAY_PAUSE = 8; // 0x8
+    field public static final int FLAG_KEY_MEDIA_POSITION_UPDATE = 256; // 0x100
     field public static final int FLAG_KEY_MEDIA_PREVIOUS = 1; // 0x1
     field public static final int FLAG_KEY_MEDIA_REWIND = 2; // 0x2
     field public static final int FLAG_KEY_MEDIA_STOP = 32; // 0x20
@@ -12297,6 +12376,14 @@
     field public static final int BITMAP_KEY_ARTWORK = 100; // 0x64
   }
 
+  public static abstract interface RemoteControlClient.OnGetPlaybackPositionListener {
+    method public abstract long onGetPlaybackPosition();
+  }
+
+  public static abstract interface RemoteControlClient.OnPlaybackPositionUpdateListener {
+    method public abstract void onPlaybackPositionUpdate(long);
+  }
+
   public class Ringtone {
     method public int getStreamType();
     method public java.lang.String getTitle(android.content.Context);
@@ -15864,7 +15951,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
@@ -15947,6 +16034,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);
@@ -16564,6 +17121,7 @@
     method public int getThreadId();
     method protected void onLooperPrepared();
     method public boolean quit();
+    method public boolean quitSafely();
   }
 
   public abstract interface IBinder {
@@ -16604,6 +17162,7 @@
     method public static void prepare();
     method public static void prepareMainLooper();
     method public void quit();
+    method public void quitSafely();
     method public void setMessageLogging(android.util.Printer);
   }
 
@@ -17074,7 +17633,7 @@
   }
 
   public class UserManager {
-    method public static synchronized android.os.UserManager get(android.content.Context);
+    method public android.os.Bundle getApplicationRestrictions(java.lang.String);
     method public long getSerialNumberForUser(android.os.UserHandle);
     method public int getUserCount();
     method public android.os.UserHandle getUserForSerialNumber(long);
@@ -21013,7 +21572,7 @@
     method public int getLac();
     method public int getMcc();
     method public int getMnc();
-    method public int getPsc();
+    method public deprecated int getPsc();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
   }
@@ -21029,6 +21588,17 @@
     field public static final android.os.Parcelable.Creator CREATOR;
   }
 
+  public final class CellIdentityWcdma implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getCid();
+    method public int getLac();
+    method public int getMcc();
+    method public int getMnc();
+    method public int getPsc();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
   public abstract class CellInfo implements android.os.Parcelable {
     method public int describeContents();
     method public long getTimeStamp();
@@ -21058,6 +21628,13 @@
     field public static final android.os.Parcelable.Creator CREATOR;
   }
 
+  public final class CellInfoWcdma extends android.telephony.CellInfo implements android.os.Parcelable {
+    method public android.telephony.CellIdentityWcdma getCellIdentity();
+    method public android.telephony.CellSignalStrengthWcdma getCellSignalStrength();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
   public abstract class CellLocation {
     ctor public CellLocation();
     method public static android.telephony.CellLocation getEmpty();
@@ -21113,6 +21690,17 @@
     field public static final android.os.Parcelable.Creator CREATOR;
   }
 
+  public final class CellSignalStrengthWcdma extends android.telephony.CellSignalStrength implements android.os.Parcelable {
+    method public int describeContents();
+    method public boolean equals(java.lang.Object);
+    method public int getAsuLevel();
+    method public int getDbm();
+    method public int getLevel();
+    method public int hashCode();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
   public class NeighboringCellInfo implements android.os.Parcelable {
     ctor public deprecated NeighboringCellInfo();
     ctor public deprecated NeighboringCellInfo(int, int);
@@ -29567,7 +30155,6 @@
     method public void setRelativeScrollPosition(int, int);
     method public deprecated void setRemoteAdapter(int, int, android.content.Intent);
     method public void setRemoteAdapter(int, android.content.Intent);
-    method public void setRemoteAdapter(int, java.util.ArrayList<android.widget.RemoteViews>, int);
     method public void setScrollPosition(int, int);
     method public void setShort(int, java.lang.String, short);
     method public void setString(int, java.lang.String, 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/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 31de98d..1e3d5be 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -308,6 +308,8 @@
      *     android:accessibilityFlags="flagDefault"
      *     android:settingsActivity="foo.bar.TestBackActivity"
      *     android:canRetrieveWindowContent="true"
+     *     android:canRequestTouchExplorationMode="true"
+     *     android:canRequestEnhancedWebAccessibility="true"
      *     . . .
      * /&gt;</pre>
      */
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index d82b9a3..40f45b7 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -29,6 +29,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.AttributeSet;
+import android.util.SparseArray;
 import android.util.TypedValue;
 import android.util.Xml;
 import android.view.View;
@@ -38,7 +39,12 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import com.android.internal.R;
+
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * This class describes an {@link AccessibilityService}. The system notifies an
@@ -61,6 +67,49 @@
     private static final String TAG_ACCESSIBILITY_SERVICE = "accessibility-service";
 
     /**
+     * Capability: This accessibility service can retrieve the active window content.
+     */
+    public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 0x00000001;
+
+    /**
+     * Capability: This accessibility service can request touch exploration mode in which
+     * touched items are spoken aloud and the UI can be explored via gestures.
+     */
+    public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 0x00000002;
+
+    /**
+     * Capability: This accessibility service can request enhanced web accessibility
+     * enhancements. For example, installing scripts to make app content more accessible.
+     */
+    public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000004;
+
+    /**
+      * Capability: This accessibility service can request to filter the key event stream.
+     */
+    public static final int CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 0x00000008;
+
+    private static final SparseArray<CapabilityInfo> sAvailableCapabilityInfos =
+            new SparseArray<CapabilityInfo>();
+    static {
+        sAvailableCapabilityInfos.put(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT,
+                new CapabilityInfo(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT,
+                        R.string.capability_title_canRetrieveWindowContent,
+                        R.string.capability_desc_canRetrieveWindowContent));
+        sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION,
+                new CapabilityInfo(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION,
+                        R.string.capability_title_canRequestTouchExploration,
+                        R.string.capability_desc_canRequestTouchExploration));
+        sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY,
+                new CapabilityInfo(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY,
+                        R.string.capability_title_canRequestEnhancedWebAccessibility,
+                        R.string.capability_desc_canRequestEnhancedWebAccessibility));
+        sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS,
+                new CapabilityInfo(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS,
+                        R.string.capability_title_canRequestFilterKeyEvents,
+                        R.string.capability_desc_canRequestFilterKeyEvents));
+    }
+
+    /**
      * Denotes spoken feedback.
      */
     public static final int FEEDBACK_SPOKEN = 0x0000001;
@@ -152,9 +201,11 @@
      * <p>
      * For accessibility services targeting API version higher than
      * {@link Build.VERSION_CODES#JELLY_BEAN_MR1} that want to set
-     * this flag have to request the
-     * {@link android.Manifest.permission#CAN_REQUEST_TOUCH_EXPLORATION_MODE}
-     * permission or the flag will be ignored.
+     * this flag have to declare this capability in their meta-data by setting
+     * the attribute {@link android.R.attr#canRequestTouchExplorationMode
+     * canRequestTouchExplorationMode} to true, otherwise this flag will
+     * be ignored. For how to declare the meta-data of a service refer to
+     * {@value AccessibilityService#SERVICE_META_DATA}.
      * </p>
      * <p>
      * Services targeting API version equal to or lower than
@@ -175,9 +226,11 @@
      * device will not have enhanced web accessibility enabled since there may be
      * another enabled service that requested it.
      * <p>
-     * Clients that want to set this flag have to request the
-     * {@link android.Manifest.permission#CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY}
-     * permission or the flag will be ignored.
+     * Services that want to set this flag have to declare this capability
+     * in their meta-data by setting the attribute {@link android.R.attr
+     * #canRequestEnhancedWebAccessibility canRequestEnhancedWebAccessibility} to
+     * true, otherwise this flag will be ignored. For how to declare the meta-data
+     * of a service refer to {@value AccessibilityService#SERVICE_META_DATA}.
      * </p>
      */
     public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000008;
@@ -192,6 +245,25 @@
     public static final int FLAG_REPORT_VIEW_IDS = 0x00000010;
 
     /**
+     * This flag requests from the system to filter key events. If this flag
+     * is set the accessibility service will receive the key events before
+     * applications allowing it implement global shortcuts. Setting this flag
+     * does not guarantee that this service will filter key events since only
+     * one service can do so at any given time. This avoids user confusion due
+     * to behavior change in case different key filtering services are enabled.
+     * If there is already another key filtering service enabled, this one will
+     * not receive key events.
+     * <p>
+     * Services that want to set this flag have to declare this capability
+     * in their meta-data by setting the attribute {@link android.R.attr
+     * #canRequestFilterKeyEvents canRequestFilterKeyEvents} to true,
+     * otherwise this flag will be ignored. For how to declare the meta-data
+     * of a service refer to {@value AccessibilityService#SERVICE_META_DATA}.
+     * </p>
+     */
+    public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 0x00000020;
+
+    /**
      * The event types an {@link AccessibilityService} is interested in.
      * <p>
      *   <strong>Can be dynamically set at runtime.</strong>
@@ -259,6 +331,9 @@
      * @see #DEFAULT
      * @see #FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
      * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE
+     * @see #FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY
+     * @see #FLAG_REQUEST_FILTER_KEY_EVENTS
+     * @see #FLAG_REPORT_VIEW_IDS
      */
     public int flags;
 
@@ -279,9 +354,9 @@
     private String mSettingsActivityName;
 
     /**
-     * Flag whether this accessibility service can retrieve window content.
+     * Bit mask with capabilities of this service.
      */
-    private boolean mCanRetrieveWindowContent;
+    private int mCapabilities;
 
     /**
      * Resource id of the description of the accessibility service.
@@ -360,9 +435,22 @@
                     com.android.internal.R.styleable.AccessibilityService_accessibilityFlags, 0);
             mSettingsActivityName = asAttributes.getString(
                     com.android.internal.R.styleable.AccessibilityService_settingsActivity);
-            mCanRetrieveWindowContent = asAttributes.getBoolean(
-                    com.android.internal.R.styleable.AccessibilityService_canRetrieveWindowContent,
-                    false);
+            if (asAttributes.getBoolean(com.android.internal.R.styleable
+                    .AccessibilityService_canRetrieveWindowContent, false)) {
+                mCapabilities |= CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT;
+            }
+            if (asAttributes.getBoolean(com.android.internal.R.styleable
+                    .AccessibilityService_canRequestTouchExplorationMode, false)) {
+                mCapabilities |= CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION;
+            }
+            if (asAttributes.getBoolean(com.android.internal.R.styleable
+                    .AccessibilityService_canRequestEnhancedWebAccessibility, false)) {
+                mCapabilities |= CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY;
+            }
+            if (asAttributes.getBoolean(com.android.internal.R.styleable
+                    .AccessibilityService_canRequestFilterKeyEvents, false)) {
+                mCapabilities |= CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS;
+            }
             TypedValue peekedValue = asAttributes.peekValue(
                     com.android.internal.R.styleable.AccessibilityService_description);
             if (peekedValue != null) {
@@ -446,9 +534,26 @@
      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
      * </p>
      * @return True if window content can be retrieved.
+     *
+     * @deprecated Use {@link #getCapabilities()}.
      */
     public boolean getCanRetrieveWindowContent() {
-        return mCanRetrieveWindowContent;
+        return (mCapabilities & CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0;
+    }
+
+    /**
+     * Returns the bit mask of capabilities this accessibility service has such as
+     * being able to retrieve the active window content, etc.
+     *
+     * @return The capability bit mask.
+     *
+     * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
+     * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
+     * @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY
+     * @see #CAPABILITY_FILTER_KEY_EVENTS
+     */
+    public int getCapabilities() {
+        return mCapabilities;
     }
 
     /**
@@ -502,7 +607,7 @@
         parcel.writeString(mId);
         parcel.writeParcelable(mResolveInfo, 0);
         parcel.writeString(mSettingsActivityName);
-        parcel.writeInt(mCanRetrieveWindowContent ? 1 : 0);
+        parcel.writeInt(mCapabilities);
         parcel.writeInt(mDescriptionResId);
         parcel.writeString(mNonLocalizedDescription);
     }
@@ -516,7 +621,7 @@
         mId = parcel.readString();
         mResolveInfo = parcel.readParcelable(null);
         mSettingsActivityName = parcel.readString();
-        mCanRetrieveWindowContent = (parcel.readInt() == 1);
+        mCapabilities = parcel.readInt();
         mDescriptionResId = parcel.readInt();
         mNonLocalizedDescription = parcel.readString();
     }
@@ -567,7 +672,7 @@
         stringBuilder.append(", ");
         stringBuilder.append("settingsActivityName: ").append(mSettingsActivityName);
         stringBuilder.append(", ");
-        stringBuilder.append("retrieveScreenContent: ").append(mCanRetrieveWindowContent);
+        appendCapabilities(stringBuilder, mCapabilities);
         return stringBuilder.toString();
     }
 
@@ -628,6 +733,20 @@
         stringBuilder.append("]");
     }
 
+    private static void appendCapabilities(StringBuilder stringBuilder, int capabilities) {
+        stringBuilder.append("capabilities:");
+        stringBuilder.append("[");
+        while (capabilities != 0) {
+            final int capabilityBit = (1 << Integer.numberOfTrailingZeros(capabilities));
+            stringBuilder.append(capabilityToString(capabilityBit));
+            capabilities &= ~capabilityBit;
+            if (capabilities != 0) {
+                stringBuilder.append(", ");
+            }
+        }
+        stringBuilder.append("]");
+    }
+
     /**
      * Returns the string representation of a feedback type. For example,
      * {@link #FEEDBACK_SPOKEN} is represented by the string FEEDBACK_SPOKEN.
@@ -699,12 +818,77 @@
                 return "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS";
             case FLAG_REQUEST_TOUCH_EXPLORATION_MODE:
                 return "FLAG_REQUEST_TOUCH_EXPLORATION_MODE";
+            case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
+                return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
+            case FLAG_REPORT_VIEW_IDS:
+                return "FLAG_REPORT_VIEW_IDS";
+            case FLAG_REQUEST_FILTER_KEY_EVENTS:
+                return "FLAG_REQUEST_FILTER_KEY_EVENTS";
             default:
                 return null;
         }
     }
 
     /**
+     * Returns the string representation of a capability. For example,
+     * {@link #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT} is represented
+     * by the string CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT.
+     *
+     * @param capability The capability.
+     * @return The string representation.
+     */
+    public static String capabilityToString(int capability) {
+        switch (capability) {
+            case CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT:
+                return "CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT";
+            case CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION:
+                return "CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION";
+            case CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
+                return "CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
+            case CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS:
+                return "CAPABILITY_CAN_FILTER_KEY_EVENTS";
+            default:
+                return "UNKNOWN";
+        }
+    }
+
+    /**
+     * @hide
+     * @return The list of {@link CapabilityInfo} objects.
+     */
+    public List<CapabilityInfo> getCapabilityInfos() {
+        if (mCapabilities == 0) {
+            return Collections.emptyList();
+        }
+        int capabilities = mCapabilities;
+        List<CapabilityInfo> capabilityInfos = new ArrayList<CapabilityInfo>();
+        while (capabilities != 0) {
+            final int capabilityBit = 1 << Integer.numberOfTrailingZeros(capabilities);
+            capabilities &= ~capabilityBit;
+            CapabilityInfo capabilityInfo = sAvailableCapabilityInfos.get(capabilityBit);
+            if (capabilityInfo != null) {
+                capabilityInfos.add(capabilityInfo);
+            }
+        }
+        return capabilityInfos;
+    }
+
+    /**
+     * @hide
+     */
+    public static final class CapabilityInfo {
+        public final int capability;
+        public final int titleResId;
+        public final int descResId;
+
+        public CapabilityInfo(int capability, int titleResId, int descResId) {
+            this.capability = capability;
+            this.titleResId = titleResId;
+            this.descResId = descResId;
+        }
+    }
+
+    /**
      * @see Parcelable.Creator
      */
     public static final Parcelable.Creator<AccessibilityServiceInfo> CREATOR =
diff --git a/core/java/android/animation/Animatable.java b/core/java/android/animation/Animatable.java
deleted file mode 100644
index f9ccb4d..0000000
--- a/core/java/android/animation/Animatable.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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.animation;
-
-/**
- * This interface is implemented by animation-related classes that expose
- * the ability to set and get duration, startDelay, and interpolators.
- */
-public interface Animatable {
-
-    /**
-     * The amount of time, in milliseconds, to delay processing the animation
-     * after the animation is started. The {@link #setDuration(long)} of the
-     * animation will not begin to elapse until after the startDelay has elapsed.
-     *
-     * @return the number of milliseconds to delay running the animation
-     */
-    long getStartDelay();
-
-    /**
-     * The amount of time, in milliseconds, to delay processing the animation
-     * after the animation is started. The {@link #setDuration(long)} of the
-     * animation will not begin to elapse until after the startDelay has elapsed.
-
-     * @param startDelay The amount of the delay, in milliseconds
-     */
-    void setStartDelay(long startDelay);
-
-    /**
-     * Sets the length of the animation.
-     *
-     * @param duration The length of the animation, in milliseconds.
-     */
-    Animatable setDuration(long duration);
-
-    /**
-     * Gets the duration of the animation.
-     *
-     * @return The length of the animation, in milliseconds.
-     */
-    long getDuration();
-
-    /**
-     * The time interpolator used in calculating the elapsed fraction of the
-     * animation. The interpolator determines whether the animation runs with
-     * linear or non-linear motion, such as acceleration and deceleration.
-     *
-     * @param value the interpolator to be used by this animation
-     */
-    void setInterpolator(TimeInterpolator value);
-
-    /**
-     * Returns the timing interpolator that this animation uses.
-     *
-     * @return The timing interpolator for this animation.
-     */
-    public TimeInterpolator getInterpolator();
-}
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index da97d72..39eb8d6 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -22,21 +22,13 @@
  * This is the superclass for classes which provide basic support for animations which can be
  * started, ended, and have <code>AnimatorListeners</code> added to them.
  */
-public abstract class Animator implements Cloneable, Animatable {
+public abstract class Animator implements Cloneable {
 
     /**
      * The set of listeners to be sent events through the life of an animation.
      */
     ArrayList<AnimatorListener> mListeners = null;
 
-    @Override
-    public abstract Animator setDuration(long duration);
-
-    @Override
-    public TimeInterpolator getInterpolator() {
-        return null;
-    }
-
     /**
      * Starts this animation. If the animation has a nonzero startDelay, the animation will start
      * running after that delay elapses. A non-delayed animation will have its initial
@@ -77,6 +69,55 @@
     }
 
     /**
+     * The amount of time, in milliseconds, to delay processing the animation
+     * after {@link #start()} is called.
+     *
+     * @return the number of milliseconds to delay running the animation
+     */
+    public abstract long getStartDelay();
+
+    /**
+     * The amount of time, in milliseconds, to delay processing the animation
+     * after {@link #start()} is called.
+
+     * @param startDelay The amount of the delay, in milliseconds
+     */
+    public abstract void setStartDelay(long startDelay);
+
+    /**
+     * Sets the duration of the animation.
+     *
+     * @param duration The length of the animation, in milliseconds.
+     */
+    public abstract Animator setDuration(long duration);
+
+    /**
+     * Gets the duration of the animation.
+     *
+     * @return The length of the animation, in milliseconds.
+     */
+    public abstract long getDuration();
+
+    /**
+     * The time interpolator used in calculating the elapsed fraction of the
+     * animation. The interpolator determines whether the animation runs with
+     * linear or non-linear motion, such as acceleration and deceleration. The
+     * default value is {@link android.view.animation.AccelerateDecelerateInterpolator}.
+     *
+     * @param value the interpolator to be used by this animation
+     */
+    public abstract void setInterpolator(TimeInterpolator value);
+
+    /**
+     * Returns the timing interpolator that this animation uses.
+     *
+     * @return The timing interpolator for this animation.
+     */
+    public TimeInterpolator getInterpolator() {
+        return null;
+    }
+
+    /**
      * Returns whether this Animator is currently running (having been started and gone past any
      * initial startDelay period and not yet ended).
      *
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index a26bdbc..6b5df7f 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1353,8 +1353,8 @@
      * of the assist Intent.  The default implementation does nothing.
      *
      * <p>This function will be called after any global assist callbacks that had
-     * been registered with {@link Application#registerOnProvideAssistData
-     * Application.registerOnProvideAssistData}.
+     * been registered with {@link Application#registerOnProvideAssistDataListener
+     * Application.registerOnProvideAssistDataListener}.
      */
     public void onProvideAssistData(Bundle data) {
     }
diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java
index 7b07438..75e4bab 100644
--- a/core/java/android/app/Application.java
+++ b/core/java/android/app/Application.java
@@ -17,17 +17,14 @@
 package android.app;
 
 import java.util.ArrayList;
-import java.util.List;
 
 import android.content.ComponentCallbacks;
 import android.content.ComponentCallbacks2;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.Intent;
-import android.content.RestrictionEntry;
 import android.content.res.Configuration;
 import android.os.Bundle;
-import android.os.UserManager;
 
 /**
  * Base class for those who need to maintain global application state. You can
@@ -49,7 +46,7 @@
             new ArrayList<ComponentCallbacks>();
     private ArrayList<ActivityLifecycleCallbacks> mActivityLifecycleCallbacks =
             new ArrayList<ActivityLifecycleCallbacks>();
-    private ArrayList<OnProvideAssistData> mAssistCallbacks = null;
+    private ArrayList<OnProvideAssistDataListener> mAssistCallbacks = null;
 
     /** @hide */
     public LoadedApk mLoadedApk;
@@ -65,10 +62,10 @@
     }
 
     /**
-     * Callback interface for use with {@link Application#registerOnProvideAssistData}
-     * and {@link Application#unregisterOnProvideAssistData}.
+     * Callback interface for use with {@link Application#registerOnProvideAssistDataListener}
+     * and {@link Application#unregisterOnProvideAssistDataListener}.
      */
-    public interface OnProvideAssistData {
+    public interface OnProvideAssistDataListener {
         /**
          * This is called when the user is requesting an assist, to build a full
          * {@link Intent#ACTION_ASSIST} Intent with all of the context of the current
@@ -134,11 +131,6 @@
         }
     }
 
-    public List<RestrictionEntry> getApplicationRestrictions() {
-        return ((UserManager) getSystemService(USER_SERVICE))
-                .getApplicationRestrictions(getPackageName(), android.os.Process.myUserHandle());
-    }
-
     public void registerComponentCallbacks(ComponentCallbacks callback) {
         synchronized (mComponentCallbacks) {
             mComponentCallbacks.add(callback);
@@ -163,16 +155,16 @@
         }
     }
 
-    public void registerOnProvideAssistData(OnProvideAssistData callback) {
+    public void registerOnProvideAssistDataListener(OnProvideAssistDataListener callback) {
         synchronized (this) {
             if (mAssistCallbacks == null) {
-                mAssistCallbacks = new ArrayList<OnProvideAssistData>();
+                mAssistCallbacks = new ArrayList<OnProvideAssistDataListener>();
             }
             mAssistCallbacks.add(callback);
         }
     }
 
-    public void unregisterOnProvideAssistData(OnProvideAssistData callback) {
+    public void unregisterOnProvideAssistDataListener(OnProvideAssistDataListener callback) {
         synchronized (this) {
             if (mAssistCallbacks != null) {
                 mAssistCallbacks.remove(callback);
@@ -285,7 +277,7 @@
         }
         if (callbacks != null) {
             for (int i=0; i<callbacks.length; i++) {
-                ((OnProvideAssistData)callbacks[i]).onProvideAssistData(activity, data);
+                ((OnProvideAssistDataListener)callbacks[i]).onProvideAssistData(activity, data);
             }
         }
     }
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/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 2e9c9e3..3498bb8 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -20,7 +20,6 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.content.Context;
 import android.os.Binder;
-import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
 import android.os.ParcelUuid;
@@ -30,11 +29,14 @@
 import android.util.Pair;
 
 import java.io.IOException;
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.HashMap;
 import java.util.LinkedList;
+import java.util.Map;
 import java.util.Random;
 import java.util.Set;
 import java.util.UUID;
@@ -357,9 +359,7 @@
     private final IBluetoothManager mManagerService;
     private IBluetooth mService;
 
-    private Handler mServiceRecordHandler;
-    private BluetoothAdapterCallback mCallback;
-    private int mClientIf;
+    private final Map<LeScanCallback, GattCallbackWrapper> mLeScanClients;
 
     /**
      * Get a handle to the default local Bluetooth adapter.
@@ -394,7 +394,7 @@
             mService = managerService.registerAdapter(mManagerCallback);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         mManagerService = managerService;
-        mServiceRecordHandler = null;
+        mLeScanClients = new HashMap<LeScanCallback, GattCallbackWrapper>();
     }
 
     /**
@@ -1409,72 +1409,38 @@
     }
 
     /**
-     * Register an callback to receive async results, such as LE scan result.
+     * Callback interface used to deliver LE scan results.
      *
-     * <p>This is an asynchronous call. The callback
-     * {@link BluetoothAdapterCallback#onCallbackRegistration}
-     * is used to notify success or failure if the function returns true.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param callback BluetootAdapter callback handler that will receive asynchronous callbacks.
-     * @return If true, the callback will be called to notify success or failure,
-     *         false on immediate error
+     * @see #startLeScan(LeScanCallback)
+     * @see #startLeScan(UUID[], LeScanCallback)
      */
-    public boolean registerCallback(BluetoothAdapterCallback callback) {
-        try {
-            IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt();
-            mCallback = callback;
-            UUID uuid = UUID.randomUUID();
-            if (DBG) Log.d(TAG, "registerCallback() - UUID=" + uuid);
-
-            iGatt.registerClient(new ParcelUuid(uuid), mBluetoothGattCallback);
-            return true;
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-            return false;
-        }
-    }
-
-    /**
-     * Unregister the registered callback.
-     */
-    public boolean unRegisterCallback(BluetoothAdapterCallback callback) {
-        if (callback != mCallback) return false;
-        try {
-            IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt();
-
-            iGatt.unregisterClient(mClientIf);
-            return true;
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-            return false;
-        }
+    public interface LeScanCallback {
+        /**
+         * Callback reporting an LE device found during a device scan initiated
+         * by the {@link BluetoothAdapter#startLeScan} function.
+         *
+         * @param device Identifies the remote device
+         * @param rssi The RSSI value for the remote device as reported by the
+         *             Bluetooth hardware. 0 if no RSSI value is available.
+         * @param scanRecord The content of the advertisement record offered by
+         *                   the remote device.
+         */
+        public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord);
     }
 
     /**
      * Starts a scan for Bluetooth LE devices.
      *
      * <p>Results of the scan are reported using the
-     * {@link BluetoothAdapterCallback#onLeScan} callback.
+     * {@link LeScanCallback#onLeScan} callback.
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
+     * @param callback the callback LE scan results are delivered
      * @return true, if the scan was started successfully
      */
-    public boolean startLeScan() {
-        if (DBG) Log.d(TAG, "startLeScan()");
-        if (mClientIf == 0) return false;
-
-        try {
-            IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt();
-            iGatt.startScan(mClientIf, false);
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-            return false;
-        }
-
-        return true;
+    public boolean startLeScan(LeScanCallback callback) {
+        return startLeScan(null, callback);
     }
 
     /**
@@ -1482,155 +1448,281 @@
      * advertise given services.
      *
      * <p>Devices which advertise all specified services are reported using the
-     * {@link BluetoothAdapterCallback#onLeScan} callback.
+     * {@link LeScanCallback#onLeScan} callback.
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
      * @param serviceUuids Array of services to look for
+     * @param callback the callback LE scan results are delivered
      * @return true, if the scan was started successfully
      */
-    public boolean startLeScan(UUID[] serviceUuids) {
-        if (DBG) Log.d(TAG, "startLeScan() - with UUIDs");
-        if (mClientIf == 0) return false;
+    public boolean startLeScan(UUID[] serviceUuids, LeScanCallback callback) {
+        if (DBG) Log.d(TAG, "startLeScan(): " + serviceUuids);
 
-        try {
-            IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt();
-            ParcelUuid[] uuids = new ParcelUuid[serviceUuids.length];
-            for(int i = 0; i != uuids.length; ++i) {
-                uuids[i] = new ParcelUuid(serviceUuids[i]);
-            }
-            iGatt.startScanWithUuids(mClientIf, false, uuids);
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
+        if (callback == null) {
+            if (DBG) Log.e(TAG, "startLeScan: null callback");
             return false;
         }
 
-        return true;
+        synchronized(mLeScanClients) {
+            if (mLeScanClients.containsKey(callback)) {
+                if (DBG) Log.e(TAG, "LE Scan has already started");
+                return false;
+            }
+
+            try {
+                IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
+                UUID uuid = UUID.randomUUID();
+                GattCallbackWrapper wrapper = new GattCallbackWrapper(this, callback, serviceUuids);
+
+                iGatt.registerClient(new ParcelUuid(uuid), wrapper);
+                if (wrapper.scanStarted()) {
+                    mLeScanClients.put(callback, wrapper);
+                    return true;
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG,"",e);
+            }
+        }
+        return false;
     }
 
     /**
      * Stops an ongoing Bluetooth LE device scan.
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param callback used to identify which scan to stop
+     *        must be the same handle used to start the scan
      */
-    public void stopLeScan() {
-        if (DBG) Log.d(TAG, "stopScan()");
-        if (mClientIf == 0) return;
-
-        try {
-            IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt();
-            iGatt.stopScan(mClientIf, false);
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
+    public void stopLeScan(LeScanCallback callback) {
+        if (DBG) Log.d(TAG, "stopLeScan()");
+        GattCallbackWrapper wrapper;
+        synchronized(mLeScanClients) {
+            wrapper = mLeScanClients.remove(callback);
+            if (wrapper == null) return;
         }
+        wrapper.stopLeScan();
     }
 
     /**
      * Bluetooth GATT interface callbacks
      */
-    private final IBluetoothGattCallback mBluetoothGattCallback =
-        new IBluetoothGattCallback.Stub() {
-            /**
-             * Application interface registered - app is ready to go
-             */
-            public void onClientRegistered(int status, int clientIf) {
-                if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status
-                    + " clientIf=" + clientIf);
-                mClientIf = clientIf;
-                mCallback.onCallbackRegistration(status == BluetoothGatt.GATT_SUCCESS ?
-                                  BluetoothAdapterCallback.CALLBACK_REGISTERED :
-                                  BluetoothAdapterCallback.CALLBACK_REGISTRATION_FAILURE);
-            }
+    private static class GattCallbackWrapper extends IBluetoothGattCallback.Stub {
+        private static final int LE_CALLBACK_REG_TIMEOUT = 2000;
+        private static final int LE_CALLBACK_REG_WAIT_COUNT = 5;
 
-            public void onClientConnectionState(int status, int clientIf,
-                                                boolean connected, String address) {
-                // no op
-            }
+        private final LeScanCallback mLeScanCb;
+        // mLeHandle 0: not registered
+        //           -1: scan stopped
+        //           >0: registered and scan started
+        private int mLeHandle;
+        private final UUID[] mScanFilter;
+        private WeakReference<BluetoothAdapter> mBluetoothAdapter;
 
-            /**
-             * Callback reporting an LE scan result.
-             * @hide
-             */
-            public void onScanResult(String address, int rssi, byte[] advData) {
-                if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi);
+        public GattCallbackWrapper(BluetoothAdapter bluetoothAdapter,
+                                   LeScanCallback leScanCb, UUID[] uuid) {
+            mBluetoothAdapter = new WeakReference<BluetoothAdapter>(bluetoothAdapter);
+            mLeScanCb = leScanCb;
+            mScanFilter = uuid;
+            mLeHandle = 0;
+        }
 
-                try {
-                    mCallback.onLeScan(getRemoteDevice(address), rssi, advData);
-                } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception: " + ex);
+        public boolean scanStarted() {
+            boolean started = false;
+            synchronized(this) {
+                if (mLeHandle == -1) return false;
+
+                int count = 0;
+                // wait for callback registration and LE scan to start
+                while (mLeHandle == 0 && count < LE_CALLBACK_REG_WAIT_COUNT) {
+                    try {
+                        wait(LE_CALLBACK_REG_TIMEOUT);
+                    } catch (InterruptedException e) {
+                        Log.e(TAG, "Callback reg wait interrupted: " + e);
+                    }
+                    count++;
                 }
+                started = (mLeHandle > 0);
             }
+            return started;
+        }
 
-            public void onGetService(String address, int srvcType,
-                                     int srvcInstId, ParcelUuid srvcUuid) {
-                // no op
+        public void stopLeScan() {
+            synchronized(this) {
+                if (mLeHandle <= 0) {
+                    Log.e(TAG, "Error state, mLeHandle: " + mLeHandle);
+                    return;
+                }
+                BluetoothAdapter adapter = mBluetoothAdapter.get();
+                if (adapter != null) {
+                    try {
+                        IBluetoothGatt iGatt = adapter.getBluetoothManager().getBluetoothGatt();
+                        iGatt.stopScan(mLeHandle, false);
+                        iGatt.unregisterClient(mLeHandle);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Failed to stop scan and unregister" + e);
+                    }
+                } else {
+                    Log.e(TAG, "stopLeScan, BluetoothAdapter is null");
+                }
+                mLeHandle = -1;
+                notifyAll();
             }
+        }
 
-            public void onGetIncludedService(String address, int srvcType,
-                                             int srvcInstId, ParcelUuid srvcUuid,
-                                             int inclSrvcType, int inclSrvcInstId,
-                                             ParcelUuid inclSrvcUuid) {
-                // no op
+        /**
+         * Application interface registered - app is ready to go
+         */
+        public void onClientRegistered(int status, int clientIf) {
+            if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status +
+                           " clientIf=" + clientIf);
+            synchronized(this) {
+                if (mLeHandle == -1) {
+                    if (DBG) Log.d(TAG, "onClientRegistered LE scan canceled");
+                }
+
+                if (status == BluetoothGatt.GATT_SUCCESS) {
+                    mLeHandle = clientIf;
+                    IBluetoothGatt iGatt = null;
+                    try {
+                        BluetoothAdapter adapter = mBluetoothAdapter.get();
+                        if (adapter != null) {
+                            iGatt = adapter.getBluetoothManager().getBluetoothGatt();
+                            if (mScanFilter == null) {
+                                iGatt.startScan(mLeHandle, false);
+                            } else {
+                                ParcelUuid[] uuids = new ParcelUuid[mScanFilter.length];
+                                for(int i = 0; i != uuids.length; ++i) {
+                                    uuids[i] = new ParcelUuid(mScanFilter[i]);
+                                }
+                                iGatt.startScanWithUuids(mLeHandle, false, uuids);
+                            }
+                        } else {
+                            Log.e(TAG, "onClientRegistered, BluetoothAdapter null");
+                            mLeHandle = -1;
+                        }
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "fail to start le scan: " + e);
+                        mLeHandle = -1;
+                    }
+                    if (mLeHandle == -1) {
+                        // registration succeeded but start scan failed
+                        if (iGatt != null) {
+                            try {
+                                iGatt.unregisterClient(mLeHandle);
+                            } catch (RemoteException e) {
+                                Log.e(TAG, "fail to unregister callback: " + mLeHandle +
+                                      " error: " + e);
+                            }
+                        }
+                    }
+                } else {
+                    // registration failed
+                    mLeHandle = -1;
+                }
+                notifyAll();
             }
+        }
 
-            public void onGetCharacteristic(String address, int srvcType,
-                             int srvcInstId, ParcelUuid srvcUuid,
-                             int charInstId, ParcelUuid charUuid,
-                             int charProps) {
-                // no op
+        public void onClientConnectionState(int status, int clientIf,
+                                            boolean connected, String address) {
+            // no op
+        }
+
+        /**
+         * Callback reporting an LE scan result.
+         * @hide
+         */
+        public void onScanResult(String address, int rssi, byte[] advData) {
+            if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi);
+
+            // Check null in case the scan has been stopped
+            synchronized(this) {
+                if (mLeHandle <= 0) return;
             }
-
-            public void onGetDescriptor(String address, int srvcType,
-                             int srvcInstId, ParcelUuid srvcUuid,
-                             int charInstId, ParcelUuid charUuid,
-                             ParcelUuid descUuid) {
-                // no op
+            try {
+                BluetoothAdapter adapter = mBluetoothAdapter.get();
+                if (adapter == null) {
+                    Log.d(TAG, "onScanResult, BluetoothAdapter null");
+                    return;
+                }
+                mLeScanCb.onLeScan(adapter.getRemoteDevice(address), rssi, advData);
+            } catch (Exception ex) {
+                Log.w(TAG, "Unhandled exception: " + ex);
             }
+        }
 
-            public void onSearchComplete(String address, int status) {
-                // no op
-            }
+        public void onGetService(String address, int srvcType,
+                                 int srvcInstId, ParcelUuid srvcUuid) {
+            // no op
+        }
 
-            public void onCharacteristicRead(String address, int status, int srvcType,
-                             int srvcInstId, ParcelUuid srvcUuid,
-                             int charInstId, ParcelUuid charUuid, byte[] value) {
-                // no op
-            }
+        public void onGetIncludedService(String address, int srvcType,
+                                         int srvcInstId, ParcelUuid srvcUuid,
+                                         int inclSrvcType, int inclSrvcInstId,
+                                         ParcelUuid inclSrvcUuid) {
+            // no op
+        }
 
-            public void onCharacteristicWrite(String address, int status, int srvcType,
-                             int srvcInstId, ParcelUuid srvcUuid,
-                             int charInstId, ParcelUuid charUuid) {
-                // no op
-            }
+        public void onGetCharacteristic(String address, int srvcType,
+                                        int srvcInstId, ParcelUuid srvcUuid,
+                                        int charInstId, ParcelUuid charUuid,
+                                        int charProps) {
+            // no op
+        }
 
-            public void onNotify(String address, int srvcType,
+        public void onGetDescriptor(String address, int srvcType,
+                                    int srvcInstId, ParcelUuid srvcUuid,
+                                    int charInstId, ParcelUuid charUuid,
+                                    ParcelUuid descUuid) {
+            // no op
+        }
+
+        public void onSearchComplete(String address, int status) {
+            // no op
+        }
+
+        public void onCharacteristicRead(String address, int status, int srvcType,
+                                         int srvcInstId, ParcelUuid srvcUuid,
+                                         int charInstId, ParcelUuid charUuid, byte[] value) {
+            // no op
+        }
+
+        public void onCharacteristicWrite(String address, int status, int srvcType,
+                                          int srvcInstId, ParcelUuid srvcUuid,
+                                          int charInstId, ParcelUuid charUuid) {
+            // no op
+        }
+
+        public void onNotify(String address, int srvcType,
                              int srvcInstId, ParcelUuid srvcUuid,
                              int charInstId, ParcelUuid charUuid,
                              byte[] value) {
-                // no op
-            }
+            // no op
+        }
 
-            public void onDescriptorRead(String address, int status, int srvcType,
-                             int srvcInstId, ParcelUuid srvcUuid,
-                             int charInstId, ParcelUuid charUuid,
-                             ParcelUuid descrUuid, byte[] value) {
-                // no op
-            }
+        public void onDescriptorRead(String address, int status, int srvcType,
+                                     int srvcInstId, ParcelUuid srvcUuid,
+                                     int charInstId, ParcelUuid charUuid,
+                                     ParcelUuid descrUuid, byte[] value) {
+            // no op
+        }
 
-            public void onDescriptorWrite(String address, int status, int srvcType,
-                             int srvcInstId, ParcelUuid srvcUuid,
-                             int charInstId, ParcelUuid charUuid,
-                             ParcelUuid descrUuid) {
-                // no op
-            }
+        public void onDescriptorWrite(String address, int status, int srvcType,
+                                      int srvcInstId, ParcelUuid srvcUuid,
+                                      int charInstId, ParcelUuid charUuid,
+                                      ParcelUuid descrUuid) {
+            // no op
+        }
 
-            public void onExecuteWrite(String address, int status) {
-                // no op
-            }
+        public void onExecuteWrite(String address, int status) {
+            // no op
+        }
 
-            public void onReadRemoteRssi(String address, int rssi, int status) {
-                // no op
-            }
-        };
+        public void onReadRemoteRssi(String address, int rssi, int status) {
+            // no op
+        }
+    }
 
 }
diff --git a/core/java/android/bluetooth/BluetoothAdapterCallback.java b/core/java/android/bluetooth/BluetoothAdapterCallback.java
deleted file mode 100644
index a726bc9..0000000
--- a/core/java/android/bluetooth/BluetoothAdapterCallback.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.bluetooth;
-
-import android.bluetooth.BluetoothDevice;
-
-/**
- * This abstract class is used to implement {@link BluetoothAdapter} callbacks.
- */
-public abstract class BluetoothAdapterCallback {
-
-    /**
-     * Indicates the callback has been registered successfully
-     */
-    public static final int CALLBACK_REGISTERED = 0;
-
-    /**
-     * Indicates the callback registration has failed
-     */
-    public static final int CALLBACK_REGISTRATION_FAILURE = 1;
-
-    /**
-     * Callback to inform change in registration state of the  application.
-     *
-     * @param status Returns {@link #CALLBACK_REGISTERED} if the application
-     *               was successfully registered.
-     */
-    public void onCallbackRegistration(int status) {
-    }
-
-    /**
-     * Callback reporting an LE device found during a device scan initiated
-     * by the {@link BluetoothAdapter#startLeScan} function.
-     *
-     * @param device Identifies the remote device
-     * @param rssi The RSSI value for the remote device as reported by the
-     *             Bluetooth hardware. 0 if no RSSI value is available.
-     * @param scanRecord The content of the advertisement record offered by
-     *                   the remote device.
-     */
-    public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
-    }
-}
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index 19083b5..172f3bc 100644
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -127,7 +127,7 @@
 
         try {
             IBluetoothManager managerService = mAdapter.getBluetoothManager();
-            IBluetoothGatt iGatt = (IBluetoothGatt) managerService.getBluetoothGatt();
+            IBluetoothGatt iGatt = managerService.getBluetoothGatt();
             if (iGatt == null) return connectedDevices;
 
             connectedDevices = iGatt.getDevicesMatchingConnectionStates(
@@ -172,7 +172,7 @@
 
         try {
             IBluetoothManager managerService = mAdapter.getBluetoothManager();
-            IBluetoothGatt iGatt = (IBluetoothGatt) managerService.getBluetoothGatt();
+            IBluetoothGatt iGatt = managerService.getBluetoothGatt();
             if (iGatt == null) return devices;
             devices = iGatt.getDevicesMatchingConnectionStates(states);
         } catch (RemoteException e) {
@@ -203,7 +203,7 @@
 
         try {
             IBluetoothManager managerService = mAdapter.getBluetoothManager();
-            IBluetoothGatt iGatt = (IBluetoothGatt) managerService.getBluetoothGatt();
+            IBluetoothGatt iGatt = managerService.getBluetoothGatt();
             if (iGatt == null) {
                 Log.e(TAG, "Fail to get GATT Server connection");
                 return null;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 03e241a..5bd28b9 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -293,15 +293,6 @@
     public abstract Context getApplicationContext();
 
     /**
-     * Returns the list of restrictions for the application, or null if there are no
-     * restrictions.
-     * @return
-     */
-    public List<RestrictionEntry> getApplicationRestrictions() {
-        return getApplicationContext().getApplicationRestrictions();
-    }
-
-    /**
      * Add a new {@link ComponentCallbacks} to the base application of the
      * Context, which will be called at the same times as the ComponentCallbacks
      * methods of activities and other components are called.  Note that you
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 97ad7dd..1ab1eb8 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2417,11 +2417,16 @@
 
     /**
      * Broadcast to a specific application to query any supported restrictions to impose
-     * on restricted users. The response should contain an extra {@link #EXTRA_RESTRICTIONS},
+     * on restricted users. The broadcast intent contains an extra
+     * {@link #EXTRA_RESTRICTIONS_BUNDLE} with the currently persisted
+     * restrictions as a Bundle of key/value pairs. The value types can be Boolean, String or
+     * String[] depending on the restriction type.<p/>
+     * The response should contain an extra {@link #EXTRA_RESTRICTIONS_LIST},
      * which is of type <code>ArrayList&lt;RestrictionEntry&gt;</code>. It can also
      * contain an extra {@link #EXTRA_RESTRICTIONS_INTENT}, which is of type <code>Intent</code>.
      * The activity specified by that intent will be launched for a result which must contain
-     * the extra {@link #EXTRA_RESTRICTIONS}. The returned restrictions will be persisted.
+     * the extra {@link #EXTRA_RESTRICTIONS_LIST}. The keys and values of the returned restrictions
+     * will be persisted.
      * @see RestrictionEntry
      */
     public static final String ACTION_GET_RESTRICTION_ENTRIES =
@@ -3160,7 +3165,8 @@
         "android.intent.extra.ALLOW_MULTIPLE";
 
     /**
-     * The userHandle carried with broadcast intents related to addition, removal and switching of users
+     * The userHandle carried with broadcast intents related to addition, removal and switching of
+     * users
      * - {@link #ACTION_USER_ADDED}, {@link #ACTION_USER_REMOVED} and {@link #ACTION_USER_SWITCHED}.
      * @hide
      */
@@ -3169,9 +3175,18 @@
 
     /**
      * Extra used in the response from a BroadcastReceiver that handles
-     * {@link #ACTION_GET_RESTRICTION_ENTRIES}.
+     * {@link #ACTION_GET_RESTRICTION_ENTRIES}. The type of the extra is
+     * <code>ArrayList&lt;RestrictionEntry&gt;</code>.
      */
-    public static final String EXTRA_RESTRICTIONS = "android.intent.extra.restrictions";
+    public static final String EXTRA_RESTRICTIONS_LIST = "android.intent.extra.restrictions_list";
+
+    /**
+     * Extra sent in the intent to the BroadcastReceiver that handles
+     * {@link #ACTION_GET_RESTRICTION_ENTRIES}. The type of the extra is a Bundle containing
+     * the restrictions as key/value pairs.
+     */
+    public static final String EXTRA_RESTRICTIONS_BUNDLE =
+            "android.intent.extra.restrictions_bundle";
 
     /**
      * Extra used in the response from a BroadcastReceiver that handles
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 3586573..acb3725 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1817,11 +1817,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/hardware/location/GeofenceHardware.java b/core/java/android/hardware/location/GeofenceHardware.java
index 35bbb9c..e67d0d7 100644
--- a/core/java/android/hardware/location/GeofenceHardware.java
+++ b/core/java/android/hardware/location/GeofenceHardware.java
@@ -129,6 +129,9 @@
 
     private HashMap<GeofenceHardwareCallback, GeofenceHardwareCallbackWrapper>
             mCallbacks = new HashMap<GeofenceHardwareCallback, GeofenceHardwareCallbackWrapper>();
+    private HashMap<GeofenceHardwareMonitorCallback, GeofenceHardwareMonitorCallbackWrapper>
+            mMonitorCallbacks = new HashMap<GeofenceHardwareMonitorCallback,
+                    GeofenceHardwareMonitorCallbackWrapper>();
     /**
      * @hide
      */
@@ -137,8 +140,29 @@
     }
 
     /**
-     * Returns all the hardware geofence monitoring systems and their status.
-     * Status can be one of {@link #MONITOR_CURRENTLY_AVAILABLE},
+     * Returns all the hardware geofence monitoring systems which are supported
+     *
+     * <p> Call {@link #getStatusOfMonitoringType(int)} to know the current state
+     * of a monitoring system.
+     *
+     * <p> Requires {@link android.Manifest.permission#LOCATION_HARDWARE} permission to access
+     * geofencing in hardware.
+     *
+     * @return An array of all the monitoring types.
+     *         An array of length 0 is returned in case of errors.
+     */
+    public int[] getMonitoringTypes() {
+        try {
+            return mService.getMonitoringTypes();
+        } catch (RemoteException e) {
+        }
+        return new int[0];
+    }
+
+    /**
+     * Returns current status of a hardware geofence monitoring system.
+     *
+     * <p>Status can be one of {@link #MONITOR_CURRENTLY_AVAILABLE},
      * {@link #MONITOR_CURRENTLY_UNAVAILABLE} or {@link #MONITOR_UNSUPPORTED}
      *
      * <p> Some supported hardware monitoring systems might not be available
@@ -147,18 +171,15 @@
      * geofences and will change from {@link #MONITOR_CURRENTLY_AVAILABLE} to
      * {@link #MONITOR_CURRENTLY_UNAVAILABLE}.
      *
-     * <p> Requires {@link android.Manifest.permission#LOCATION_HARDWARE} permission to access
-     * geofencing in hardware.
-     *
-     * @return An array indexed by the various monitoring types and their status.
-     *         An array of length 0 is returned in case of errors.
+     * @param monitoringType
+     * @return Current status of the monitoring type.
      */
-    public int[] getMonitoringTypesAndStatus() {
+    public int getStatusOfMonitoringType(int monitoringType) {
         try {
-            return mService.getMonitoringTypesAndStatus();
+            return mService.getStatusOfMonitoringType(monitoringType);
         } catch (RemoteException e) {
+            return MONITOR_UNSUPPORTED;
         }
-        return new int[0];
     }
 
     /**
@@ -167,8 +188,10 @@
      * <p> When the device detects that is has entered, exited or is uncertain
      * about the area specified by the geofence, the given callback will be called.
      *
-     * <p> The {@link GeofenceHardwareCallback#onGeofenceChange} callback will be called,
-     * with the following parameters
+     * <p> If this call returns true, it means that the geofence has been sent to the hardware.
+     * {@link GeofenceHardwareCallback#onGeofenceAdd} will be called with the result of the
+     * add call from the hardware. The {@link GeofenceHardwareCallback#onGeofenceAdd} will be
+     * called with the following parameters when a transition event occurs.
      * <ul>
      * <li> The geofence Id
      * <li> The location object indicating the last known location.
@@ -195,43 +218,46 @@
      * which abstracts the hardware should be used instead. All the checks are done by the higher
      * level public API. Any needed locking should be handled by the higher level API.
      *
-     * @param latitude Latitude of the area to be monitored.
-     * @param longitude Longitude of the area to be monitored.
-     * @param radius Radius (in meters) of the area to be monitored.
-     * @param lastTransition The current state of the geofence. Can be one of
-     *        {@link #GEOFENCE_ENTERED}, {@link #GEOFENCE_EXITED},
-     *        {@link #GEOFENCE_UNCERTAIN}.
-     * @param monitorTransitions Bitwise OR of {@link #GEOFENCE_ENTERED},
-     *        {@link #GEOFENCE_EXITED}, {@link #GEOFENCE_UNCERTAIN}
-     * @param notificationResponsivenes Defines the best-effort description
-     *        of how soon should the callback be called when the transition
-     *        associated with the Geofence is triggered. For instance, if
-     *        set to 1000 millseconds with {@link #GEOFENCE_ENTERED},
-     *        the callback will be called 1000 milliseconds within entering
-     *        the geofence. This parameter is defined in milliseconds.
-     * @param unknownTimer The time limit after which the
-     *        {@link #GEOFENCE_UNCERTAIN} transition
-     *        should be triggered. This paramter is defined in milliseconds.
+     * <p> Create a geofence request object using the methods in {@link GeofenceHardwareRequest} to
+     * set all the characteristics of the geofence. Use the created GeofenceHardwareRequest object
+     * in this call.
+     *
+     * @param geofenceId The id associated with the geofence.
      * @param monitoringType The type of the hardware subsystem that should be used
      *        to monitor the geofence.
+     * @param geofenceRequest The {@link GeofenceHardwareRequest} object associated with the
+     *        geofence.
      * @param callback {@link GeofenceHardwareCallback} that will be use to notify the
      *        transition.
-     * @return true on success.
+     * @return true when the geofence is successfully sent to the hardware for addition.
+     * @throws IllegalArgumentException when the geofence request type is not supported.
      */
-    public boolean addCircularFence(int geofenceId, double latitude, double longitude,
-            double radius, int lastTransition,int monitorTransitions, int notificationResponsivenes,
-            int unknownTimer, int monitoringType, GeofenceHardwareCallback callback) {
+    public boolean addGeofence(int geofenceId, int monitoringType, GeofenceHardwareRequest
+            geofenceRequest, GeofenceHardwareCallback callback) {
         try {
-            return mService.addCircularFence(geofenceId, latitude, longitude, radius,
-                    lastTransition, monitorTransitions, notificationResponsivenes, unknownTimer,
-                    monitoringType, getCallbackWrapper(callback));
+            if (geofenceRequest.getType() == GeofenceHardwareRequest.GEOFENCE_TYPE_CIRCLE) {
+                return mService.addCircularFence(geofenceId, monitoringType,
+                        geofenceRequest.getLatitude(),
+                        geofenceRequest.getLongitude(), geofenceRequest.getRadius(),
+                        geofenceRequest.getLastTransition(),
+                        geofenceRequest.getMonitorTransitions(),
+                        geofenceRequest.getNotificationResponsiveness(),
+                        geofenceRequest.getUnknownTimer(),
+                        getCallbackWrapper(callback));
+            } else {
+                throw new IllegalArgumentException("Geofence Request type not supported");
+            }
         } catch (RemoteException e) {
         }
         return false;
     }
 
     /**
-     * Removes a geofence added by {@link #addCircularFence} call.
+     * Removes a geofence added by {@link #addGeofence} call.
+     *
+     * <p> If this call returns true, it means that the geofence has been sent to the hardware.
+     * {@link GeofenceHardwareCallback#onGeofenceRemove} will be called with the result of the
+     * remove call from the hardware.
      *
      * <p> Requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission when
      * {@link #MONITORING_TYPE_GPS_HARDWARE} is used.
@@ -246,7 +272,7 @@
      * @param geofenceId The id of the geofence.
      * @param monitoringType The type of the hardware subsystem that should be used
      *        to monitor the geofence.
-     * @return true on success.
+     * @return true when the geofence is successfully sent to the hardware for removal.                     .
      */
    public boolean removeGeofence(int geofenceId, int monitoringType) {
        try {
@@ -257,7 +283,11 @@
    }
 
     /**
-     * Pauses the monitoring of a geofence added by {@link #addCircularFence} call.
+     * Pauses the monitoring of a geofence added by {@link #addGeofence} call.
+     *
+     * <p> If this call returns true, it means that the geofence has been sent to the hardware.
+     * {@link GeofenceHardwareCallback#onGeofencePause} will be called with the result of the
+     * pause call from the hardware.
      *
      * <p> Requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission when
      * {@link #MONITORING_TYPE_GPS_HARDWARE} is used.
@@ -272,7 +302,7 @@
      * @param geofenceId The id of the geofence.
      * @param monitoringType The type of the hardware subsystem that should be used
      *        to monitor the geofence.
-     * @return true on success.
+     * @return true when the geofence is successfully sent to the hardware for pausing.
      */
     public boolean pauseGeofence(int geofenceId, int monitoringType) {
         try {
@@ -285,6 +315,10 @@
     /**
      * Resumes the monitoring of a geofence added by {@link #pauseGeofence} call.
      *
+     * <p> If this call returns true, it means that the geofence has been sent to the hardware.
+     * {@link GeofenceHardwareCallback#onGeofenceResume} will be called with the result of the
+     * resume call from the hardware.
+     *
      * <p> Requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission when
      * {@link #MONITORING_TYPE_GPS_HARDWARE} is used.
      *
@@ -296,15 +330,15 @@
      * level public API. Any needed locking should be handled by the higher level API.
      *
      * @param geofenceId The id of the geofence.
-     * @param monitorTransition Bitwise OR of {@link #GEOFENCE_ENTERED},
-     *        {@link #GEOFENCE_EXITED}, {@link #GEOFENCE_UNCERTAIN}
      * @param monitoringType The type of the hardware subsystem that should be used
      *        to monitor the geofence.
-     * @return true on success.
+     * @param monitorTransition Bitwise OR of {@link #GEOFENCE_ENTERED},
+     *        {@link #GEOFENCE_EXITED}, {@link #GEOFENCE_UNCERTAIN}
+     * @return true when the geofence is successfully sent to the hardware for resumption.
      */
-    public boolean resumeGeofence(int geofenceId, int monitorTransition, int monitoringType) {
+    public boolean resumeGeofence(int geofenceId, int monitoringType, int monitorTransition) {
         try {
-            return mService.resumeGeofence(geofenceId, monitorTransition, monitoringType);
+            return mService.resumeGeofence(geofenceId, monitoringType, monitorTransition);
         } catch (RemoteException e) {
         }
         return false;
@@ -333,10 +367,10 @@
      * @return true on success
      */
     public boolean registerForMonitorStateChangeCallback(int monitoringType,
-            GeofenceHardwareCallback callback) {
+            GeofenceHardwareMonitorCallback callback) {
         try {
             return mService.registerForMonitorStateChangeCallback(monitoringType,
-                    getCallbackWrapper(callback));
+                    getMonitorCallbackWrapper(callback));
         } catch (RemoteException e) {
         }
         return false;
@@ -361,12 +395,12 @@
      * @return true on success
      */
     public boolean unregisterForMonitorStateChangeCallback(int monitoringType,
-            GeofenceHardwareCallback callback) {
+            GeofenceHardwareMonitorCallback callback) {
         boolean  result = false;
         try {
             result = mService.unregisterForMonitorStateChangeCallback(monitoringType,
-                    getCallbackWrapper(callback));
-            if (result) removeCallback(callback);
+                    getMonitorCallbackWrapper(callback));
+            if (result) removeMonitorCallback(callback);
 
         } catch (RemoteException e) {
         }
@@ -391,6 +425,38 @@
         }
     }
 
+    private void removeMonitorCallback(GeofenceHardwareMonitorCallback callback) {
+        synchronized (mMonitorCallbacks) {
+            mMonitorCallbacks.remove(callback);
+        }
+    }
+
+    private GeofenceHardwareMonitorCallbackWrapper getMonitorCallbackWrapper(
+            GeofenceHardwareMonitorCallback callback) {
+        synchronized (mMonitorCallbacks) {
+            GeofenceHardwareMonitorCallbackWrapper wrapper = mMonitorCallbacks.get(callback);
+            if (wrapper == null) {
+                wrapper = new GeofenceHardwareMonitorCallbackWrapper(callback);
+                mMonitorCallbacks.put(callback, wrapper);
+            }
+            return wrapper;
+        }
+    }
+
+    class GeofenceHardwareMonitorCallbackWrapper extends IGeofenceHardwareMonitorCallback.Stub {
+        private WeakReference<GeofenceHardwareMonitorCallback> mCallback;
+
+        GeofenceHardwareMonitorCallbackWrapper(GeofenceHardwareMonitorCallback c) {
+            mCallback = new WeakReference<GeofenceHardwareMonitorCallback>(c);
+        }
+
+        public void onMonitoringSystemChange(int monitoringType, boolean available,
+                Location location) {
+            GeofenceHardwareMonitorCallback c = mCallback.get();
+            if (c != null) c.onMonitoringSystemChange(monitoringType, available, location);
+        }
+    }
+
     class GeofenceHardwareCallbackWrapper extends IGeofenceHardwareCallback.Stub {
         private WeakReference<GeofenceHardwareCallback> mCallback;
 
@@ -398,17 +464,11 @@
             mCallback = new WeakReference<GeofenceHardwareCallback>(c);
         }
 
-        public void onMonitoringSystemChange(int monitoringType, boolean available,
-                Location location) {
-            GeofenceHardwareCallback c = mCallback.get();
-            if (c != null) c.onMonitoringSystemChange(monitoringType, available, location);
-        }
-
-        public void onGeofenceChange(int geofenceId, int transition, Location location,
+        public void onGeofenceTransition(int geofenceId, int transition, Location location,
                 long timestamp, int monitoringType) {
             GeofenceHardwareCallback c = mCallback.get();
             if (c != null) {
-                c.onGeofenceChange(geofenceId, transition, location, timestamp,
+                c.onGeofenceTransition(geofenceId, transition, location, timestamp,
                         monitoringType);
             }
         }
@@ -428,7 +488,9 @@
 
         public void onGeofencePause(int geofenceId, int status) {
             GeofenceHardwareCallback c = mCallback.get();
-            if (c != null) c.onGeofencePause(geofenceId, status);
+            if (c != null) {
+                c.onGeofencePause(geofenceId, status);
+            }
         }
 
         public void onGeofenceResume(int geofenceId, int status) {
diff --git a/core/java/android/hardware/location/GeofenceHardwareCallback.java b/core/java/android/hardware/location/GeofenceHardwareCallback.java
index 8ab582a..6cad3da 100644
--- a/core/java/android/hardware/location/GeofenceHardwareCallback.java
+++ b/core/java/android/hardware/location/GeofenceHardwareCallback.java
@@ -22,19 +22,6 @@
  * The callback class associated with the APIs in {@link GeofenceHardware}
  */
 public abstract class GeofenceHardwareCallback {
-
-    /**
-     * The callback called when the state of a monitoring system changes.
-     * {@link GeofenceHardware#MONITORING_TYPE_GPS_HARDWARE} is an example of a
-     * monitoring system.
-     *
-     * @param monitoringType The type of the monitoring system.
-     * @param available Indicates whether the system is currently available or not.
-     * @param location The last known location according to the monitoring system.
-     */
-    public void onMonitoringSystemChange(int monitoringType, boolean available, Location location) {
-    }
-
     /**
      * The callback called when there is a transition to report for the specific
      * geofence.
@@ -47,7 +34,7 @@
      *        detected
      * @param monitoringType Type of the monitoring system.
      */
-    public void onGeofenceChange(int geofenceId, int transition, Location location,
+    public void onGeofenceTransition(int geofenceId, int transition, Location location,
             long timestamp, int monitoringType) {
     }
 
diff --git a/core/java/android/hardware/location/GeofenceHardwareImpl.java b/core/java/android/hardware/location/GeofenceHardwareImpl.java
index 21f1ea6..a62b660 100644
--- a/core/java/android/hardware/location/GeofenceHardwareImpl.java
+++ b/core/java/android/hardware/location/GeofenceHardwareImpl.java
@@ -21,8 +21,10 @@
 import android.location.IGpsGeofenceHardware;
 import android.location.Location;
 import android.location.LocationManager;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.RemoteException;
@@ -48,8 +50,9 @@
     private PowerManager.WakeLock mWakeLock;
     private SparseArray<IGeofenceHardwareCallback> mGeofences =
             new SparseArray<IGeofenceHardwareCallback>();
-    private ArrayList<IGeofenceHardwareCallback>[] mCallbacks =
+    private ArrayList<IGeofenceHardwareMonitorCallback>[] mCallbacks =
             new ArrayList[GeofenceHardware.NUM_MONITORS];
+    private ArrayList<Reaper> mReapers = new ArrayList<Reaper>();
 
     private IGpsGeofenceHardware mGpsService;
 
@@ -63,11 +66,18 @@
     private static final int RESUME_GEOFENCE_CALLBACK = 5;
     private static final int ADD_GEOFENCE = 6;
     private static final int REMOVE_GEOFENCE = 7;
+    private static final int GEOFENCE_CALLBACK_BINDER_DIED = 8;
 
     // mCallbacksHandler message types
     private static final int GPS_GEOFENCE_STATUS = 1;
     private static final int CALLBACK_ADD = 2;
     private static final int CALLBACK_REMOVE = 3;
+    private static final int MONITOR_CALLBACK_BINDER_DIED = 4;
+
+    // mReaperHandler message types
+    private static final int REAPER_GEOFENCE_ADDED = 1;
+    private static final int REAPER_MONITOR_CALLBACK_ADDED = 2;
+    private static final int REAPER_REMOVED = 3;
 
     // The following constants need to match GpsLocationFlags enum in gps.h
     private static final int LOCATION_INVALID = 0;
@@ -151,15 +161,28 @@
         }
     }
 
-    public int[] getMonitoringTypesAndStatus() {
+    public int[] getMonitoringTypes() {
         synchronized (mSupportedMonitorTypes) {
-            return mSupportedMonitorTypes;
+            if (mSupportedMonitorTypes[GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE] !=
+                        GeofenceHardware.MONITOR_UNSUPPORTED) {
+                return new int[] {GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE};
+            }
+            return new int[0];
         }
     }
 
-    public boolean addCircularFence(int geofenceId, double latitude, double longitude,
-            double radius, int lastTransition,int monitorTransitions, int notificationResponsivenes,
-            int unknownTimer, int monitoringType, IGeofenceHardwareCallback callback) {
+    public int getStatusOfMonitoringType(int monitoringType) {
+        synchronized (mSupportedMonitorTypes) {
+            if (monitoringType >= mSupportedMonitorTypes.length || monitoringType < 0) {
+                throw new IllegalArgumentException("Unknown monitoring type");
+            }
+            return mSupportedMonitorTypes[monitoringType];
+        }
+    }
+
+    public boolean addCircularFence(int geofenceId,  int monitoringType, double latitude,
+            double longitude, double radius, int lastTransition,int monitorTransitions,
+            int notificationResponsivenes, int unknownTimer, IGeofenceHardwareCallback callback) {
         // This API is not thread safe. Operations on the same geofence need to be serialized
         // by upper layers
         if (DEBUG) {
@@ -190,7 +213,11 @@
             default:
                 result = false;
         }
-        if (!result) {
+        if (result) {
+            m = mReaperHandler.obtainMessage(REAPER_GEOFENCE_ADDED, callback);
+            m.arg1 = monitoringType;
+            mReaperHandler.sendMessage(m);
+        } else {
             m = mGeofenceHandler.obtainMessage(REMOVE_GEOFENCE);
             m.arg1 = geofenceId;
             mGeofenceHandler.sendMessage(m);
@@ -245,7 +272,7 @@
     }
 
 
-    public boolean resumeGeofence(int geofenceId, int monitorTransition, int monitoringType) {
+    public boolean resumeGeofence(int geofenceId,  int monitoringType, int monitorTransition) {
         // This API is not thread safe. Operations on the same geofence need to be serialized
         // by upper layers
         if (DEBUG) Log.d(TAG, "Resume Geofence: GeofenceId: " + geofenceId);
@@ -268,7 +295,12 @@
     }
 
     public boolean registerForMonitorStateChangeCallback(int monitoringType,
-            IGeofenceHardwareCallback callback) {
+            IGeofenceHardwareMonitorCallback callback) {
+        Message reaperMessage =
+                mReaperHandler.obtainMessage(REAPER_MONITOR_CALLBACK_ADDED, callback);
+        reaperMessage.arg1 = monitoringType;
+        mReaperHandler.sendMessage(reaperMessage);
+
         Message m = mCallbacksHandler.obtainMessage(CALLBACK_ADD, callback);
         m.arg1 = monitoringType;
         mCallbacksHandler.sendMessage(m);
@@ -276,7 +308,7 @@
     }
 
     public boolean unregisterForMonitorStateChangeCallback(int monitoringType,
-            IGeofenceHardwareCallback callback) {
+            IGeofenceHardwareMonitorCallback callback) {
         Message m = mCallbacksHandler.obtainMessage(CALLBACK_REMOVE, callback);
         m.arg1 = monitoringType;
         mCallbacksHandler.sendMessage(m);
@@ -477,13 +509,25 @@
                             "Location: " + geofenceTransition.mLocation + ":" + mGeofences);
 
                     try {
-                        callback.onGeofenceChange(
+                        callback.onGeofenceTransition(
                                 geofenceTransition.mGeofenceId, geofenceTransition.mTransition,
                                 geofenceTransition.mLocation, geofenceTransition.mTimestamp,
                                 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE);
                     } catch (RemoteException e) {}
                     releaseWakeLock();
                     break;
+                case GEOFENCE_CALLBACK_BINDER_DIED:
+                   // Find all geofences associated with this callback and remove them.
+                   callback = (IGeofenceHardwareCallback) (msg.obj);
+                   if (DEBUG) Log.d(TAG, "Geofence callback reaped:" + callback);
+                   int monitoringType = msg.arg1;
+                   for (int i = 0; i < mGeofences.size(); i++) {
+                        if (mGeofences.valueAt(i).equals(callback)) {
+                            geofenceId = mGeofences.keyAt(i);
+                            removeGeofence(mGeofences.keyAt(i), monitoringType);
+                            mGeofences.remove(geofenceId);
+                        }
+                   }
             }
         }
     };
@@ -493,8 +537,8 @@
         @Override
         public void handleMessage(Message msg) {
             int monitoringType;
-            ArrayList<IGeofenceHardwareCallback> callbackList;
-            IGeofenceHardwareCallback callback;
+            ArrayList<IGeofenceHardwareMonitorCallback> callbackList;
+            IGeofenceHardwareMonitorCallback callback;
 
             switch (msg.what) {
                 case GPS_GEOFENCE_STATUS:
@@ -508,7 +552,7 @@
 
                     if (DEBUG) Log.d(TAG, "MonitoringSystemChangeCallback: GPS : " + available);
 
-                    for (IGeofenceHardwareCallback c: callbackList) {
+                    for (IGeofenceHardwareMonitorCallback c: callbackList) {
                         try {
                             c.onMonitoringSystemChange(
                                     GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, available,
@@ -519,22 +563,71 @@
                     break;
                 case CALLBACK_ADD:
                     monitoringType = msg.arg1;
-                    callback = (IGeofenceHardwareCallback) msg.obj;
+                    callback = (IGeofenceHardwareMonitorCallback) msg.obj;
                     callbackList = mCallbacks[monitoringType];
                     if (callbackList == null) {
-                        callbackList = new ArrayList<IGeofenceHardwareCallback>();
+                        callbackList = new ArrayList<IGeofenceHardwareMonitorCallback>();
                         mCallbacks[monitoringType] = callbackList;
                     }
                     if (!callbackList.contains(callback)) callbackList.add(callback);
                     break;
                 case CALLBACK_REMOVE:
                     monitoringType = msg.arg1;
-                    callback = (IGeofenceHardwareCallback) msg.obj;
+                    callback = (IGeofenceHardwareMonitorCallback) msg.obj;
                     callbackList = mCallbacks[monitoringType];
                     if (callbackList != null) {
                         callbackList.remove(callback);
                     }
                     break;
+                case MONITOR_CALLBACK_BINDER_DIED:
+                    callback = (IGeofenceHardwareMonitorCallback) msg.obj;
+                    if (DEBUG) Log.d(TAG, "Monitor callback reaped:" + callback);
+                    callbackList = mCallbacks[msg.arg1];
+                    if (callbackList != null && callbackList.contains(callback)) {
+                        callbackList.remove(callback);
+                    }
+            }
+        }
+    };
+
+    // All operations on mReaper
+    private Handler mReaperHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            Reaper r;
+            IGeofenceHardwareCallback callback;
+            IGeofenceHardwareMonitorCallback monitorCallback;
+            int monitoringType;
+
+            switch (msg.what) {
+                case REAPER_GEOFENCE_ADDED:
+                    callback = (IGeofenceHardwareCallback) msg.obj;
+                    monitoringType = msg.arg1;
+                    r = new Reaper(callback, monitoringType);
+                    if (!mReapers.contains(r)) {
+                        mReapers.add(r);
+                        IBinder b = callback.asBinder();
+                        try {
+                            b.linkToDeath(r, 0);
+                        } catch (RemoteException e) {}
+                    }
+                    break;
+                case REAPER_MONITOR_CALLBACK_ADDED:
+                    monitorCallback = (IGeofenceHardwareMonitorCallback) msg.obj;
+                    monitoringType = msg.arg1;
+
+                    r = new Reaper(monitorCallback, monitoringType);
+                    if (!mReapers.contains(r)) {
+                        mReapers.add(r);
+                        IBinder b = monitorCallback.asBinder();
+                        try {
+                            b.linkToDeath(r, 0);
+                        } catch (RemoteException e) {}
+                    }
+                    break;
+                case REAPER_REMOVED:
+                    r = (Reaper) msg.obj;
+                    mReapers.remove(r);
             }
         }
     };
@@ -567,6 +660,57 @@
         return RESOLUTION_LEVEL_NONE;
     }
 
+    class Reaper implements IBinder.DeathRecipient {
+        private IGeofenceHardwareMonitorCallback mMonitorCallback;
+        private IGeofenceHardwareCallback mCallback;
+        private int mMonitoringType;
+
+        Reaper(IGeofenceHardwareCallback c, int monitoringType) {
+            mCallback = c;
+            mMonitoringType = monitoringType;
+        }
+
+        Reaper(IGeofenceHardwareMonitorCallback c, int monitoringType) {
+            mMonitorCallback = c;
+            mMonitoringType = monitoringType;
+        }
+
+        @Override
+        public void binderDied() {
+            Message m;
+            if (mCallback != null) {
+                m = mGeofenceHandler.obtainMessage(GEOFENCE_CALLBACK_BINDER_DIED, mCallback);
+                m.arg1 = mMonitoringType;
+                mGeofenceHandler.sendMessage(m);
+            } else if (mMonitorCallback != null) {
+                m = mCallbacksHandler.obtainMessage(MONITOR_CALLBACK_BINDER_DIED, mMonitorCallback);
+                m.arg1 = mMonitoringType;
+                mCallbacksHandler.sendMessage(m);
+            }
+            Message reaperMessage = mReaperHandler.obtainMessage(REAPER_REMOVED, this);
+            mReaperHandler.sendMessage(reaperMessage);
+        }
+
+        @Override
+        public int hashCode() {
+            int result = 17;
+            result = 31 * result + (mCallback != null ? mCallback.hashCode() : 0);
+            result = 31 * result + (mMonitorCallback != null ? mMonitorCallback.hashCode() : 0);
+            result = 31 * result + mMonitoringType;
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == null) return false;
+            if (obj == this) return true;
+
+            Reaper rhs = (Reaper) obj;
+            return rhs.mCallback == mCallback && rhs.mMonitorCallback == mMonitorCallback &&
+                    rhs.mMonitoringType == mMonitoringType;
+        }
+    }
+
     int getAllowedResolutionLevel(int pid, int uid) {
         if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
                 pid, uid) == PackageManager.PERMISSION_GRANTED) {
diff --git a/core/java/android/hardware/location/GeofenceHardwareMonitorCallback.java b/core/java/android/hardware/location/GeofenceHardwareMonitorCallback.java
new file mode 100644
index 0000000..b8e927e
--- /dev/null
+++ b/core/java/android/hardware/location/GeofenceHardwareMonitorCallback.java
@@ -0,0 +1,37 @@
+/*
+ * 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.hardware.location;
+
+import android.location.Location;
+
+/**
+ * The callback class associated with the status change of hardware montiors
+ * in {@link GeofenceHardware}
+ */
+public abstract class GeofenceHardwareMonitorCallback {
+    /**
+     * The callback called when the state of a monitoring system changes.
+     * {@link GeofenceHardware#MONITORING_TYPE_GPS_HARDWARE} is an example of a
+     * monitoring system
+     *
+     * @param monitoringType The type of the monitoring system.
+     * @param available Indicates whether the system is currenty available or not.
+     * @param location The last known location according to the monitoring system.
+     */
+    public void onMonitoringSystemChange(int monitoringType, boolean available, Location location) {
+    }
+}
diff --git a/core/java/android/hardware/location/GeofenceHardwareRequest.java b/core/java/android/hardware/location/GeofenceHardwareRequest.java
new file mode 100644
index 0000000..6e7b592
--- /dev/null
+++ b/core/java/android/hardware/location/GeofenceHardwareRequest.java
@@ -0,0 +1,158 @@
+/*
+ * 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.hardware.location;
+
+import android.location.Location;
+
+/**
+ * This class represents the characteristics of the geofence.
+ *
+ * <p> Use this in conjunction with {@link GeofenceHardware} APIs.
+ */
+
+public final class GeofenceHardwareRequest {
+    static final int GEOFENCE_TYPE_CIRCLE = 0;
+    private int mType;
+    private double mLatitude;
+    private double mLongitude;
+    private double mRadius;
+    private int mLastTransition = GeofenceHardware.GEOFENCE_UNCERTAIN;
+    private int mUnknownTimer = 30000; // 30 secs
+    private int mMonitorTransitions = GeofenceHardware.GEOFENCE_UNCERTAIN |
+        GeofenceHardware.GEOFENCE_ENTERED | GeofenceHardware.GEOFENCE_EXITED;
+    private int mNotificationResponsiveness = 5000; // 5 secs
+
+    private void setCircularGeofence(double latitude, double longitude, double radius) {
+        mLatitude = latitude;
+        mLongitude = longitude;
+        mRadius = radius;
+        mType  = GEOFENCE_TYPE_CIRCLE;
+    }
+
+    /**
+     * Create a circular geofence.
+     *
+     * @param latitude Latitude of the geofence
+     * @param longitude Longitude of the geofence
+     * @param radius Radius of the geofence (in meters)
+     */
+    public static GeofenceHardwareRequest createCircularGeofence(double latitude,
+            double longitude, double radius) {
+        GeofenceHardwareRequest geofenceRequest = new GeofenceHardwareRequest();
+        geofenceRequest.setCircularGeofence(latitude, longitude, radius);
+        return geofenceRequest;
+    }
+
+    /**
+     * Set the last known transition of the geofence.
+     *
+     * @param lastTransition The current state of the geofence. Can be one of
+     *        {@link GeofenceHardware#GEOFENCE_ENTERED}, {@link GeofenceHardware#GEOFENCE_EXITED},
+     *        {@link GeofenceHardware#GEOFENCE_UNCERTAIN}.
+     */
+    public void setLastTransition(int lastTransition) {
+        mLastTransition = lastTransition;
+    }
+
+    /**
+     * Set the unknown timer for this geofence.
+     *
+     * @param unknownTimer  The time limit after which the
+     *        {@link GeofenceHardware#GEOFENCE_UNCERTAIN} transition
+     *        should be triggered. This paramter is defined in milliseconds.
+     */
+    public void setUnknownTimer(int unknownTimer) {
+        mUnknownTimer = unknownTimer;
+    }
+
+    /**
+     * Set the transitions to be monitored.
+     *
+     * @param monitorTransitions Bitwise OR of {@link GeofenceHardware#GEOFENCE_ENTERED},
+     *        {@link GeofenceHardware#GEOFENCE_EXITED}, {@link GeofenceHardware#GEOFENCE_UNCERTAIN}
+     */
+    public void setMonitorTransitions(int monitorTransitions) {
+        mMonitorTransitions = monitorTransitions;
+    }
+
+    /**
+     * Set the notification responsiveness of the geofence.
+     *
+     * @param notificationResponsiveness (milliseconds) Defines the best-effort description
+     *        of how soon should the callback be called when the transition
+     *        associated with the Geofence is triggered. For instance, if
+     *        set to 1000 millseconds with {@link GeofenceHardware#GEOFENCE_ENTERED},
+     *        the callback will be called 1000 milliseconds within entering
+     *        the geofence.
+     */
+    public void setNotificationResponsiveness(int notificationResponsiveness) {
+       mNotificationResponsiveness = notificationResponsiveness;
+    }
+
+    /**
+     * Returns the latitude of this geofence.
+     */
+    public double getLatitude() {
+        return mLatitude;
+    }
+
+    /**
+     * Returns the longitude of this geofence.
+     */
+    public double getLongitude() {
+        return mLongitude;
+    }
+
+    /**
+     * Returns the radius of this geofence.
+     */
+    public double getRadius() {
+        return mRadius;
+    }
+
+    /**
+     * Returns transitions monitored for this geofence.
+     */
+    public int getMonitorTransitions() {
+        return mMonitorTransitions;
+    }
+
+    /**
+     * Returns the unknownTimer of this geofence.
+     */
+    public int getUnknownTimer() {
+        return mUnknownTimer;
+    }
+
+    /**
+     * Returns the notification responsiveness of this geofence.
+     */
+    public int getNotificationResponsiveness() {
+        return mNotificationResponsiveness;
+    }
+
+    /**
+     * Returns the last transition of this geofence.
+     */
+    public int getLastTransition() {
+        return mLastTransition;
+    }
+
+    int getType() {
+        return mType;
+    }
+}
diff --git a/core/java/android/hardware/location/GeofenceHardwareService.java b/core/java/android/hardware/location/GeofenceHardwareService.java
index 0eccee6..3bc70ee 100644
--- a/core/java/android/hardware/location/GeofenceHardwareService.java
+++ b/core/java/android/hardware/location/GeofenceHardwareService.java
@@ -68,23 +68,28 @@
             mGeofenceHardwareImpl.setGpsHardwareGeofence(service);
         }
 
-        public int[] getMonitoringTypesAndStatus() {
+        public int[] getMonitoringTypes() {
             mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
                     "Location Hardware permission not granted to access hardware geofence");
 
-            return mGeofenceHardwareImpl.getMonitoringTypesAndStatus();
+            return mGeofenceHardwareImpl.getMonitoringTypes();
         }
 
-        public boolean addCircularFence(int id, double lat, double longitude, double radius,
-                int lastTransition, int monitorTransitions, int
-                notificationResponsiveness, int unknownTimer, int monitoringType,
-                IGeofenceHardwareCallback callback) {
+        public int getStatusOfMonitoringType(int monitoringType) {
+            mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
+                    "Location Hardware permission not granted to access hardware geofence");
+
+            return mGeofenceHardwareImpl.getStatusOfMonitoringType(monitoringType);
+        }
+        public boolean addCircularFence(int id, int monitoringType, double lat, double longitude,
+                double radius, int lastTransition, int monitorTransitions, int
+                notificationResponsiveness, int unknownTimer, IGeofenceHardwareCallback callback) {
             mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
                     "Location Hardware permission not granted to access hardware geofence");
             checkPermission(Binder.getCallingPid(), Binder.getCallingUid(), monitoringType);
-            return mGeofenceHardwareImpl.addCircularFence(id, lat, longitude, radius,
-                    lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer,
-                    monitoringType, callback);
+            return mGeofenceHardwareImpl.addCircularFence(id, monitoringType, lat, longitude,
+                    radius, lastTransition, monitorTransitions, notificationResponsiveness,
+                    unknownTimer, callback);
         }
 
         public boolean removeGeofence(int id, int monitoringType) {
@@ -103,16 +108,16 @@
             return mGeofenceHardwareImpl.pauseGeofence(id, monitoringType);
         }
 
-        public boolean resumeGeofence(int id, int monitorTransitions, int monitoringType) {
+        public boolean resumeGeofence(int id, int monitoringType, int monitorTransitions) {
             mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
                     "Location Hardware permission not granted to access hardware geofence");
 
             checkPermission(Binder.getCallingPid(), Binder.getCallingUid(), monitoringType);
-            return mGeofenceHardwareImpl.resumeGeofence(id, monitorTransitions, monitoringType);
+            return mGeofenceHardwareImpl.resumeGeofence(id, monitoringType, monitorTransitions);
         }
 
         public boolean registerForMonitorStateChangeCallback(int monitoringType,
-                IGeofenceHardwareCallback callback) {
+                IGeofenceHardwareMonitorCallback callback) {
             mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
                     "Location Hardware permission not granted to access hardware geofence");
 
@@ -122,7 +127,7 @@
         }
 
         public boolean unregisterForMonitorStateChangeCallback(int monitoringType,
-                IGeofenceHardwareCallback callback) {
+                IGeofenceHardwareMonitorCallback callback) {
             mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
                     "Location Hardware permission not granted to access hardware geofence");
 
diff --git a/core/java/android/hardware/location/IGeofenceHardware.aidl b/core/java/android/hardware/location/IGeofenceHardware.aidl
index 4ba02b8..6900070 100644
--- a/core/java/android/hardware/location/IGeofenceHardware.aidl
+++ b/core/java/android/hardware/location/IGeofenceHardware.aidl
@@ -18,19 +18,21 @@
 
 import android.location.IGpsGeofenceHardware;
 import android.hardware.location.IGeofenceHardwareCallback;
+import android.hardware.location.IGeofenceHardwareMonitorCallback;
 
 /** @hide */
 interface IGeofenceHardware {
     void setGpsGeofenceHardware(in IGpsGeofenceHardware service);
-    int[] getMonitoringTypesAndStatus();
-    boolean addCircularFence(int id, double lat, double longitude, double radius,
-            int lastTransition, int monitorTransitions, int notificationResponsiveness,
-            int unknownTimer, int monitoringType, in IGeofenceHardwareCallback callback);
+    int[] getMonitoringTypes();
+    int getStatusOfMonitoringType(int monitoringType);
+    boolean addCircularFence(int id,  int monitoringType, double lat, double longitude,
+            double radius, int lastTransition, int monitorTransitions,
+            int notificationResponsiveness, int unknownTimer,in IGeofenceHardwareCallback callback);
     boolean removeGeofence(int id, int monitoringType);
     boolean pauseGeofence(int id, int monitoringType);
-    boolean resumeGeofence(int id, int monitorTransitions, int monitoringType);
+    boolean resumeGeofence(int id, int monitoringType, int monitorTransitions);
     boolean registerForMonitorStateChangeCallback(int monitoringType,
-            IGeofenceHardwareCallback callback);
+            IGeofenceHardwareMonitorCallback callback);
     boolean unregisterForMonitorStateChangeCallback(int monitoringType,
-            IGeofenceHardwareCallback callback);
+            IGeofenceHardwareMonitorCallback callback);
 }
diff --git a/core/java/android/hardware/location/IGeofenceHardwareCallback.aidl b/core/java/android/hardware/location/IGeofenceHardwareCallback.aidl
index 678fc49..3a8f430 100644
--- a/core/java/android/hardware/location/IGeofenceHardwareCallback.aidl
+++ b/core/java/android/hardware/location/IGeofenceHardwareCallback.aidl
@@ -20,8 +20,7 @@
 
 /** @hide */
 oneway interface IGeofenceHardwareCallback {
-   void onMonitoringSystemChange(int monitoringType, boolean available, in Location location);
-   void onGeofenceChange(int geofenceId, int transition, in Location location,
+   void onGeofenceTransition(int geofenceId, int transition, in Location location,
             long timestamp, int monitoringType);
    void onGeofenceAdd(int geofenceId, int status);
    void onGeofenceRemove(int geofenceId, int status);
diff --git a/core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl b/core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl
new file mode 100644
index 0000000..0b6e04b
--- /dev/null
+++ b/core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.hardware.location;
+
+import android.location.Location;
+
+/** @hide */
+oneway interface IGeofenceHardwareMonitorCallback {
+   void onMonitoringSystemChange(int monitoringType, boolean available, in Location location);
+}
diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java
index 0856e27..b2034b2 100644
--- a/core/java/android/hardware/usb/UsbDeviceConnection.java
+++ b/core/java/android/hardware/usb/UsbDeviceConnection.java
@@ -107,6 +107,11 @@
      * {@link UsbConstants#USB_DIR_OUT}, then the transfer is a write,
      * and if it is {@link UsbConstants#USB_DIR_IN}, then the transfer
      * is a read.
+     * <p>
+     * This method transfers data starting from index 0 in the buffer.
+     * To specify a different offset, use
+     * {@link #controlTransfer(int, int, int, int, byte[], int, int, int)}.
+     * </p>
      *
      * @param requestType request type for this transaction
      * @param request request ID for this transaction
@@ -118,11 +123,7 @@
      * @param timeout in milliseconds
      * @return length of data transferred (or zero) for success,
      * or negative value for failure
-     *
-     * @deprecated Use {@link #controlTransfer(int, int, int, int, byte[], int, int, int)}
-     * which accepts a buffer start index.
      */
-    @Deprecated
     public int controlTransfer(int requestType, int request, int value,
             int index, byte[] buffer, int length, int timeout) {
         return controlTransfer(requestType, request, value, index, buffer, 0, length, timeout);
@@ -142,22 +143,27 @@
      * @param index index field for this transaction
      * @param buffer buffer for data portion of transaction,
      * or null if no data needs to be sent or received
-     * @param start the index of the first byte in the buffer to send or receive
+     * @param offset the index of the first byte in the buffer to send or receive
      * @param length the length of the data to send or receive
      * @param timeout in milliseconds
      * @return length of data transferred (or zero) for success,
      * or negative value for failure
      */
     public int controlTransfer(int requestType, int request, int value, int index,
-            byte[] buffer, int start, int length, int timeout) {
-        checkBounds(buffer, start, length);
+            byte[] buffer, int offset, int length, int timeout) {
+        checkBounds(buffer, offset, length);
         return native_control_request(requestType, request, value, index,
-                buffer, start, length, timeout);
+                buffer, offset, length, timeout);
     }
 
     /**
      * Performs a bulk transaction on the given endpoint.
-     * The direction of the transfer is determined by the direction of the endpoint
+     * The direction of the transfer is determined by the direction of the endpoint.
+     * <p>
+     * This method transfers data starting from index 0 in the buffer.
+     * To specify a different offset, use
+     * {@link #bulkTransfer(UsbEndpoint, byte[], int, int, int)}.
+     * </p>
      *
      * @param endpoint the endpoint for this transaction
      * @param buffer buffer for data to send or receive
@@ -165,11 +171,7 @@
      * @param timeout in milliseconds
      * @return length of data transferred (or zero) for success,
      * or negative value for failure
-     *
-     * @deprecated Use {@link #bulkTransfer(UsbEndpoint, byte[], int, int, int)}
-     * which accepts a buffer start index.
      */
-    @Deprecated
     public int bulkTransfer(UsbEndpoint endpoint,
             byte[] buffer, int length, int timeout) {
         return bulkTransfer(endpoint, buffer, 0, length, timeout);
@@ -177,20 +179,20 @@
 
     /**
      * Performs a bulk transaction on the given endpoint.
-     * The direction of the transfer is determined by the direction of the endpoint
+     * The direction of the transfer is determined by the direction of the endpoint.
      *
      * @param endpoint the endpoint for this transaction
      * @param buffer buffer for data to send or receive
-     * @param start the index of the first byte in the buffer to send or receive
+     * @param offset the index of the first byte in the buffer to send or receive
      * @param length the length of the data to send or receive
      * @param timeout in milliseconds
      * @return length of data transferred (or zero) for success,
      * or negative value for failure
      */
     public int bulkTransfer(UsbEndpoint endpoint,
-            byte[] buffer, int start, int length, int timeout) {
-        checkBounds(buffer, start, length);
-        return native_bulk_request(endpoint.getAddress(), buffer, start, length, timeout);
+            byte[] buffer, int offset, int length, int timeout) {
+        checkBounds(buffer, offset, length);
+        return native_bulk_request(endpoint.getAddress(), buffer, offset, length, timeout);
     }
 
     /**
@@ -235,9 +237,9 @@
     private native boolean native_claim_interface(int interfaceID, boolean force);
     private native boolean native_release_interface(int interfaceID);
     private native int native_control_request(int requestType, int request, int value,
-            int index, byte[] buffer, int start, int length, int timeout);
+            int index, byte[] buffer, int offset, int length, int timeout);
     private native int native_bulk_request(int endpoint, byte[] buffer,
-            int start, int length, int timeout);
+            int offset, int length, int timeout);
     private native UsbRequest native_request_wait();
     private native String native_get_serial();
 }
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index 94de448..14d8f07 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -413,27 +413,32 @@
 
     /**
      * Runs the specified task synchronously.
-     *
+     * <p>
      * If the current thread is the same as the handler thread, then the runnable
      * runs immediately without being enqueued.  Otherwise, posts the runnable
      * to the handler and waits for it to complete before returning.
-     *
+     * </p><p>
      * This method is dangerous!  Improper use can result in deadlocks.
      * Never call this method while any locks are held or use it in a
      * possibly re-entrant manner.
-     *
+     * </p><p>
      * This method is occasionally useful in situations where a background thread
      * must synchronously await completion of a task that must run on the
      * handler's thread.  However, this problem is often a symptom of bad design.
      * Consider improving the design (if possible) before resorting to this method.
-     *
+     * </p><p>
      * One example of where you might want to use this method is when you just
      * set up a Handler thread and need to perform some initialization steps on
      * it before continuing execution.
-     *
+     * </p><p>
      * If timeout occurs then this method returns <code>false</code> but the runnable
      * will remain posted on the handler and may already be in progress or
      * complete at a later time.
+     * </p><p>
+     * When using this method, be sure to use {@link Looper#quitSafely} when
+     * quitting the looper.  Otherwise {@link #runWithScissors} may hang indefinitely.
+     * (TODO: We should fix this by making MessageQueue aware of blocking runnables.)
+     * </p>
      *
      * @param r The Runnable that will be executed synchronously.
      * @param timeout The timeout in milliseconds, or 0 to wait indefinitely.
diff --git a/core/java/android/os/HandlerThread.java b/core/java/android/os/HandlerThread.java
index daf1f59..2904105 100644
--- a/core/java/android/os/HandlerThread.java
+++ b/core/java/android/os/HandlerThread.java
@@ -48,6 +48,7 @@
     protected void onLooperPrepared() {
     }
 
+    @Override
     public void run() {
         mTid = Process.myTid();
         Looper.prepare();
@@ -83,12 +84,25 @@
         }
         return mLooper;
     }
-    
+
     /**
-     * Ask the currently running looper to quit.  If the thread has not
-     * been started or has finished (that is if {@link #getLooper} returns
-     * null), then false is returned.  Otherwise the looper is asked to
-     * quit and true is returned.
+     * Quits the handler thread's looper.
+     * <p>
+     * Causes the handler thread's looper to terminate without processing any
+     * more messages in the message queue.
+     * </p><p>
+     * Any attempt to post messages to the queue after the looper is asked to quit will fail.
+     * For example, the {@link Handler#sendMessage(Message)} method will return false.
+     * </p><p class="note">
+     * Using this method may be unsafe because some messages may not be delivered
+     * before the looper terminates.  Consider using {@link #quitSafely} instead to ensure
+     * that all pending work is completed in an orderly manner.
+     * </p>
+     *
+     * @return True if the looper looper has been asked to quit or false if the
+     * thread had not yet started running.
+     *
+     * @see #quitSafely
      */
     public boolean quit() {
         Looper looper = getLooper();
@@ -98,7 +112,34 @@
         }
         return false;
     }
-    
+
+    /**
+     * Quits the handler thread's looper safely.
+     * <p>
+     * Causes the handler thread's looper to terminate as soon as all remaining messages
+     * in the message queue that are already due to be delivered have been handled.
+     * Pending delayed messages with due times in the future will not be delivered.
+     * </p><p>
+     * Any attempt to post messages to the queue after the looper is asked to quit will fail.
+     * For example, the {@link Handler#sendMessage(Message)} method will return false.
+     * </p><p>
+     * If the thread has not been started or has finished (that is if
+     * {@link #getLooper} returns null), then false is returned.
+     * Otherwise the looper is asked to quit and true is returned.
+     * </p>
+     *
+     * @return True if the looper looper has been asked to quit or false if the
+     * thread had not yet started running.
+     */
+    public boolean quitSafely() {
+        Looper looper = getLooper();
+        if (looper != null) {
+            looper.quitSafely();
+            return true;
+        }
+        return false;
+    }
+
     /**
      * Returns the identifier of this thread. See Process.myTid().
      */
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 2e8092a..a11358a 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -42,7 +42,8 @@
     int getUserHandle(int userSerialNumber);
     Bundle getUserRestrictions(int userHandle);
     void setUserRestrictions(in Bundle restrictions, int userHandle);
-    void setApplicationRestrictions(in String packageName, in List<RestrictionEntry> entries,
+    void setApplicationRestrictions(in String packageName, in Bundle restrictions,
             int userHandle);
-    List<RestrictionEntry> getApplicationRestrictions(in String packageName, int userHandle);
+    Bundle getApplicationRestrictions(in String packageName);
+    Bundle getApplicationRestrictionsForUser(in String packageName, int userHandle);
 }
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index fa28765..d5cf771 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -202,18 +202,37 @@
     /**
      * Quits the looper.
      * <p>
-     * Causes the {@link #loop} method to terminate as soon as all remaining messages
-     * in the message queue that are already due to be delivered have been handled.
-     * However delayed messages with due times in the future may not be handled before
-     * the loop terminates.
+     * Causes the {@link #loop} method to terminate without processing any
+     * more messages in the message queue.
      * </p><p>
-     * Any attempt to post messages to the queue after {@link #quit} has been called
-     * will fail.  For example, the {@link Handler#sendMessage(Message)} method will
-     * return false when the looper is being terminated.
+     * Any attempt to post messages to the queue after the looper is asked to quit will fail.
+     * For example, the {@link Handler#sendMessage(Message)} method will return false.
+     * </p><p class="note">
+     * Using this method may be unsafe because some messages may not be delivered
+     * before the looper terminates.  Consider using {@link #quitSafely} instead to ensure
+     * that all pending work is completed in an orderly manner.
      * </p>
+     *
+     * @see #quitSafely
      */
     public void quit() {
-        mQueue.quit();
+        mQueue.quit(false);
+    }
+
+    /**
+     * Quits the looper safely.
+     * <p>
+     * Causes the {@link #loop} method to terminate as soon as all remaining messages
+     * in the message queue that are already due to be delivered have been handled.
+     * However pending delayed messages with due times in the future will not be
+     * delivered before the loop terminates.
+     * </p><p>
+     * Any attempt to post messages to the queue after the looper is asked to quit will fail.
+     * For example, the {@link Handler#sendMessage(Message)} method will return false.
+     * </p>
+     */
+    public void quitSafely() {
+        mQueue.quit(true);
     }
 
     /**
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index c058bfc..bf7e5ca 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -219,7 +219,7 @@
         }
     }
 
-    void quit() {
+    void quit(boolean safe) {
         if (!mQuitAllowed) {
             throw new RuntimeException("Main thread not allowed to quit.");
         }
@@ -229,6 +229,12 @@
                 return;
             }
             mQuiting = true;
+
+            if (safe) {
+                removeAllFutureMessagesLocked();
+            } else {
+                removeAllMessagesLocked();
+            }
         }
         nativeWake(mPtr);
     }
@@ -473,4 +479,42 @@
             }
         }
     }
+
+    private void removeAllMessagesLocked() {
+        Message p = mMessages;
+        while (p != null) {
+            Message n = p.next;
+            p.recycle();
+            p = n;
+        }
+        mMessages = null;
+    }
+
+    private void removeAllFutureMessagesLocked() {
+        final long now = SystemClock.uptimeMillis();
+        Message p = mMessages;
+        if (p != null) {
+            if (p.when > now) {
+                removeAllMessagesLocked();
+            } else {
+                Message n;
+                for (;;) {
+                    n = p.next;
+                    if (n == null) {
+                        return;
+                    }
+                    if (n.when > now) {
+                        break;
+                    }
+                    p = n;
+                }
+                p.next = null;
+                do {
+                    p = n;
+                    n = p.next;
+                    p.recycle();
+                } while (n != null);
+            }
+        }
+    }
 }
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/os/UserManager.java b/core/java/android/os/UserManager.java
index e580e2b..df065e9 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -142,6 +142,7 @@
 
     private static UserManager sInstance = null;
 
+    /** @hide */
     public synchronized static UserManager get(Context context) {
         if (sInstance == null) {
             sInstance = (UserManager) context.getSystemService(Context.USER_SERVICE);
@@ -578,13 +579,29 @@
         return -1;
     }
 
+    /**
+     * Returns a Bundle containing any saved application restrictions for this user, for the
+     * given package name. Only an application with this package name can call this method.
+     * @param packageName the package name of the calling application
+     * @return a Bundle with the restrictions as key/value pairs, or null if there are no
+     * saved restrictions. The values can be of type Boolean, String or String[], depending
+     * on the restriction type, as defined by the application.
+     */
+    public Bundle getApplicationRestrictions(String packageName) {
+        try {
+            return mService.getApplicationRestrictions(packageName);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not get application restrictions for package " + packageName);
+        }
+        return null;
+    }
 
     /**
      * @hide
      */
-    public List<RestrictionEntry> getApplicationRestrictions(String packageName, UserHandle user) {
+    public Bundle getApplicationRestrictions(String packageName, UserHandle user) {
         try {
-            return mService.getApplicationRestrictions(packageName, user.getIdentifier());
+            return mService.getApplicationRestrictionsForUser(packageName, user.getIdentifier());
         } catch (RemoteException re) {
             Log.w(TAG, "Could not get application restrictions for user " + user.getIdentifier());
         }
@@ -594,10 +611,10 @@
     /**
      * @hide
      */
-    public void setApplicationRestrictions(String packageName, List<RestrictionEntry> entries,
+    public void setApplicationRestrictions(String packageName, Bundle restrictions,
             UserHandle user) {
         try {
-            mService.setApplicationRestrictions(packageName, entries, user.getIdentifier());
+            mService.setApplicationRestrictions(packageName, restrictions, user.getIdentifier());
         } catch (RemoteException re) {
             Log.w(TAG, "Could not set application restrictions for user " + user.getIdentifier());
         }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 88ee414..4de5933 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -714,6 +714,17 @@
      */
     public static final String EXTRA_AUTHORITIES = "authorities";
 
+    /**
+     * Activity Extra: Limit available options in launched activity based on the given account
+     * types.
+     * <p>
+     * This can be passed as an extra field in an Activity Intent with one or more account types
+     * as a String[]. This field is used by some intents to alter the behavior of the called
+     * activity.
+     * <p>
+     * Example: The {@link #ACTION_ADD_ACCOUNT} intent restricts the account types to the specified
+     * list.
+     */
     public static final String EXTRA_ACCOUNT_TYPES = "account_types";
 
     public static final String EXTRA_INPUT_METHOD_ID = "input_method_id";
@@ -3260,6 +3271,7 @@
         /**
          * This preference contains the string that shows for owner info on LockScreen.
          * @hide
+         * @deprecated
          */
         public static final String LOCK_SCREEN_OWNER_INFO = "lock_screen_owner_info";
 
@@ -3287,6 +3299,7 @@
         /**
          * This preference enables showing the owner info on LockScreen.
          * @hide
+         * @deprecated
          */
         public static final String LOCK_SCREEN_OWNER_INFO_ENABLED =
             "lock_screen_owner_info_enabled";
@@ -4102,9 +4115,7 @@
             MOUNT_UMS_AUTOSTART,
             MOUNT_UMS_PROMPT,
             MOUNT_UMS_NOTIFY_ENABLED,
-            UI_NIGHT_MODE,
-            LOCK_SCREEN_OWNER_INFO,
-            LOCK_SCREEN_OWNER_INFO_ENABLED
+            UI_NIGHT_MODE
         };
 
         /**
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index edfef56..4989c3a 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -220,14 +220,14 @@
     /**
      * Gets a {@link Canvas} for drawing into this surface.
      *
-     * After drawing into the provided {@link Canvas}, the caller should
+     * After drawing into the provided {@link Canvas}, the caller must
      * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
      *
      * @param inOutDirty A rectangle that represents the dirty region that the caller wants
      * to redraw.  This function may choose to expand the dirty rectangle if for example
      * the surface has been resized or if the previous contents of the surface were
-     * not available.  The caller should redraw the entire dirty region as represented
-     * by the contents of the dirty rect upon return from this function.
+     * not available.  The caller must redraw the entire dirty region as represented
+     * by the contents of the inOutDirty rectangle upon return from this function.
      * The caller may also pass <code>null</code> instead, in the case where the
      * entire surface should be redrawn.
      * @return A canvas for drawing into the surface.
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 5d0f523..793fb5e 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();
@@ -754,12 +755,36 @@
             mHandler.sendMessage(msg);
         }
         
+        /**
+         * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
+         *
+         * After drawing into the provided {@link Canvas}, the caller must
+         * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
+         *
+         * The caller must redraw the entire surface.
+         * @return A canvas for drawing into the surface.
+         */
         public Canvas lockCanvas() {
             return internalLockCanvas(null);
         }
 
-        public Canvas lockCanvas(Rect dirty) {
-            return internalLockCanvas(dirty);
+        /**
+         * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
+         *
+         * After drawing into the provided {@link Canvas}, the caller must
+         * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
+         *
+         * @param inOutDirty A rectangle that represents the dirty region that the caller wants
+         * to redraw.  This function may choose to expand the dirty rectangle if for example
+         * the surface has been resized or if the previous contents of the surface were
+         * not available.  The caller must redraw the entire dirty region as represented
+         * by the contents of the inOutDirty rectangle upon return from this function.
+         * The caller may also pass <code>null</code> instead, in the case where the
+         * entire surface should be redrawn.
+         * @return A canvas for drawing into the surface.
+         */
+        public Canvas lockCanvas(Rect inOutDirty) {
+            return internalLockCanvas(inOutDirty);
         }
 
         private final Canvas internalLockCanvas(Rect dirty) {
@@ -809,6 +834,12 @@
             return null;
         }
 
+        /**
+         * Posts the new contents of the {@link Canvas} to the surface and
+         * releases the {@link Canvas}.
+         *
+         * @param canvas The canvas previously obtained from {@link #lockCanvas}.
+         */
         public void unlockCanvasAndPost(Canvas canvas) {
             mSurface.unlockCanvasAndPost(canvas);
             mSurfaceLock.unlock();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 4fb2431..be26d20 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -13380,18 +13380,32 @@
 
     /**
      * Sets a rectangular area on this view to which the view will be clipped
-     * it is drawn. Setting the value to null will remove the clip bounds
+     * when it is drawn. Setting the value to null will remove the clip bounds
      * and the view will draw normally, using its full bounds.
      *
      * @param clipBounds The rectangular area, in the local coordinates of
      * this view, to which future drawing operations will be clipped.
      */
     public void setClipBounds(Rect clipBounds) {
-        mClipBounds = clipBounds;
         if (clipBounds != null) {
-            invalidate(clipBounds);
+            if (clipBounds.equals(mClipBounds)) {
+                return;
+            }
+            if (mClipBounds == null) {
+                invalidate();
+                mClipBounds = new Rect(clipBounds);
+            } else {
+                invalidate(Math.min(mClipBounds.left, clipBounds.left),
+                        Math.min(mClipBounds.top, clipBounds.top),
+                        Math.max(mClipBounds.right, clipBounds.right),
+                        Math.max(mClipBounds.bottom, clipBounds.bottom));
+                mClipBounds.set(clipBounds);
+            }
         } else {
-            invalidate();
+            if (mClipBounds != null) {
+                invalidate();
+                mClipBounds = null;
+            }
         }
     }
 
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/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 98df064..528eadd 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -16,7 +16,6 @@
 
 package android.view;
 
-import android.animation.Animatable;
 import android.animation.Animator;
 import android.animation.ValueAnimator;
 import android.animation.TimeInterpolator;
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 96ef0b4..0212482 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -795,9 +795,7 @@
          * <p>This flag can be controlled in your theme through the
          * {@link android.R.attr#windowOverscan} attribute; this attribute
          * is automatically set for you in the standard overscan themes
-         * such as {@link android.R.style#Theme_NoTitleBar_Overscan},
-         * {@link android.R.style#Theme_Black_NoTitleBar_Overscan},
-         * {@link android.R.style#Theme_Light_NoTitleBar_Overscan},
+         * such as
          * {@link android.R.style#Theme_Holo_NoActionBar_Overscan},
          * {@link android.R.style#Theme_Holo_Light_NoActionBar_Overscan},
          * {@link android.R.style#Theme_DeviceDefault_NoActionBar_Overscan}, and
@@ -1012,6 +1010,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/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index c7dacf3..a324502 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -2149,7 +2149,8 @@
     @Override
     public void destroy() {
         if (mWebView.getViewRootImpl() != null) {
-            Log.e(LOGTAG, "Error: WebView.destroy() called while still attached!");
+            Log.e(LOGTAG, Log.getStackTraceString(
+                    new Throwable("Error: WebView.destroy() called while still attached!")));
         }
         ensureFunctorDetached();
         destroyJava();
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 85ed8db..2309001 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -944,15 +944,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);
@@ -979,6 +981,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();
@@ -987,29 +994,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/android/widget/ListView.java b/core/java/android/widget/ListView.java
index c7914f3..f42999d 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -41,6 +41,7 @@
 import android.view.ViewRootImpl;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeProvider;
 import android.widget.RemoteViews.RemoteView;
 
 import java.util.ArrayList;
@@ -1715,11 +1716,17 @@
             }
 
             // Attempt to restore accessibility focus.
-            if (accessibilityFocusLayoutRestoreNode != null) {
-                accessibilityFocusLayoutRestoreNode.performAction(
-                        AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
-            } else if (accessibilityFocusLayoutRestoreView != null) {
-                accessibilityFocusLayoutRestoreView.requestAccessibilityFocus();
+            if (accessibilityFocusLayoutRestoreView != null) {
+                final AccessibilityNodeProvider provider =
+                        accessibilityFocusLayoutRestoreView.getAccessibilityNodeProvider();
+                if ((accessibilityFocusLayoutRestoreNode != null) && (provider != null)) {
+                    final int virtualViewId = AccessibilityNodeInfo.getVirtualDescendantId(
+                            accessibilityFocusLayoutRestoreNode.getSourceNodeId());
+                    provider.performAction(virtualViewId,
+                            AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
+                } else {
+                    accessibilityFocusLayoutRestoreView.requestAccessibilityFocus();
+                }
             } else if (accessibilityFocusPosition != INVALID_POSITION) {
                 // Bound the position within the visible children.
                 final int position = MathUtils.constrain(
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 83e2e79..07e66b7 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -2108,6 +2108,8 @@
      *      RemoteViews. This count cannot change during the life-cycle of a given widget, so this
      *      parameter should account for the maximum possible number of types that may appear in the
      *      See {@link Adapter#getViewTypeCount()}.
+     *
+     * @hide
      */
     public void setRemoteAdapter(int viewId, ArrayList<RemoteViews> list, int viewTypeCount) {
         addAction(new SetRemoteViewsAdapterList(viewId, list, viewTypeCount));
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/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 59ff597..d69bc31 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -1354,7 +1354,7 @@
 
     public void setHomeActionContentDescription(int resId) {
         mHomeDescriptionRes = resId;
-        mHomeDescription = getResources().getText(resId);
+        mHomeDescription = resId != 0 ? getResources().getText(resId) : null;
     }
 
     static class SavedState extends BaseSavedState {
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 555c7c2..d3ead26 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -140,6 +140,10 @@
 
     public final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
 
+    private static final String LOCK_SCREEN_OWNER_INFO = Settings.Secure.LOCK_SCREEN_OWNER_INFO;
+    private static final String LOCK_SCREEN_OWNER_INFO_ENABLED =
+            Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
+
     private final Context mContext;
     private final ContentResolver mContentResolver;
     private DevicePolicyManager mDevicePolicyManager;
@@ -526,6 +530,22 @@
         }
     }
 
+    public void setOwnerInfo(String info, int userId) {
+        setString(LOCK_SCREEN_OWNER_INFO, info, userId);
+    }
+
+    public void setOwnerInfoEnabled(boolean enabled) {
+        setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled);
+    }
+
+    public String getOwnerInfo(int userId) {
+        return getString(LOCK_SCREEN_OWNER_INFO);
+    }
+
+    public boolean isOwnerInfoEnabled() {
+        return getBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, false);
+    }
+
     /**
      * Compute the password quality from the given password string.
      */
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/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 1ace23e..17f205d 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -339,23 +339,11 @@
 }
 
 TextLayoutShaper::TextLayoutShaper() {
-    init();
-
     mBuffer = hb_buffer_create();
 }
 
-void TextLayoutShaper::init() {
-    mDefaultTypeface = SkFontHost::CreateTypeface(NULL, NULL, SkTypeface::kNormal);
-}
-
-void TextLayoutShaper::unrefTypefaces() {
-    SkSafeUnref(mDefaultTypeface);
-}
-
 TextLayoutShaper::~TextLayoutShaper() {
     hb_buffer_destroy(mBuffer);
-
-    unrefTypefaces();
 }
 
 void TextLayoutShaper::computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars,
@@ -839,23 +827,27 @@
     }
 
     if (baseGlyphCount != 0) {
+        SkTypeface::Style style = SkTypeface::kNormal;
+        if (typeface != NULL) {
+            style = typeface->style();
+        }
         typeface = typefaceForScript(paint, typeface, hb_buffer_get_script(mBuffer));
         if (!typeface) {
             baseGlyphCount = 0;
-            typeface = mDefaultTypeface;
-            SkSafeRef(typeface);
+            typeface = SkFontHost::CreateTypeface(NULL, NULL, style);
 #if DEBUG_GLYPHS
             ALOGD("Using Default Typeface");
 #endif
         }
     } else {
         if (!typeface) {
-            typeface = mDefaultTypeface;
+            typeface = SkFontHost::CreateTypeface(NULL, NULL, SkTypeface::kNormal);
 #if DEBUG_GLYPHS
-            ALOGD("Using Default Typeface");
+            ALOGD("Using Default Typeface (normal style)");
 #endif
+        } else {
+            SkSafeRef(typeface);
         }
-        SkSafeRef(typeface);
     }
 
     mShapingPaint.setTypeface(typeface);
@@ -899,8 +891,6 @@
         hb_face_destroy(mCachedHBFaces.valueAt(i));
     }
     mCachedHBFaces.clear();
-    unrefTypefaces();
-    init();
 }
 
 TextLayoutEngine::TextLayoutEngine() {
diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h
index f9b9900..5414a11 100644
--- a/core/jni/android/graphics/TextLayoutCache.h
+++ b/core/jni/android/graphics/TextLayoutCache.h
@@ -197,18 +197,10 @@
     SkPaint mShapingPaint;
 
     /**
-     * Skia default typeface to be returned if we cannot resolve script
-     */
-    SkTypeface* mDefaultTypeface;
-
-    /**
      * Cache of Harfbuzz faces
      */
     KeyedVector<SkFontID, hb_face_t*> mCachedHBFaces;
 
-    void init();
-    void unrefTypefaces();
-
     SkTypeface* typefaceForScript(const SkPaint* paint, SkTypeface* typeface,
         hb_script_t script);
 
@@ -228,7 +220,6 @@
     hb_face_t* referenceCachedHBFace(SkTypeface* typeface);
 
     bool isComplexScript(hb_script_t script);
-
 }; // TextLayoutShaper
 
 /**
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/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 6b4fe79..cb14374 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -134,6 +134,7 @@
     <protected-broadcast android:name="android.net.conn.CONNECTIVITY_CHANGE" />
     <protected-broadcast android:name="android.net.conn.CONNECTIVITY_CHANGE_IMMEDIATE" />
     <protected-broadcast android:name="android.net.conn.DATA_ACTIVITY_CHANGE" />
+    <protected-broadcast android:name="android.net.conn.BACKGROUND_DATA_SETTING_CHANGED" />
     <protected-broadcast android:name="android.net.conn.CAPTIVE_PORTAL_TEST_COMPLETED" />
 
     <protected-broadcast android:name="android.nfc.action.LLCP_LINK_STATE_CHANGED" />
@@ -544,6 +545,7 @@
     <!-- =============================================== -->
     <!-- Permissions for enabling accessibility features -->
     <!-- =============================================== -->
+    <eat-comment />
 
     <!-- Used for permissions that allow requesting certain accessibility features. -->
     <permission-group android:name="android.permission-group.ACCESSIBILITY_FEATURES"
@@ -552,20 +554,6 @@
         android:description="@string/permgroupdesc_accessibilityFeatures"
         android:priority="380" />
 
-    <!-- Allows an accessibility service to request touch exploration mode. -->
-    <permission android:name="android.permission.CAN_REQUEST_TOUCH_EXPLORATION_MODE"
-        android:permissionGroup="android.permission-group.ACCESSIBILITY_FEATURES"
-        android:label="@string/permlab_canRequestTouchExplorationMode"
-        android:description="@string/permdesc_canRequestTouchExplorationMode"
-        android:protectionLevel="dangerous" />
-
-    <!-- Allows an accessibility service to request enhanced web accessibility. -->
-    <permission android:name="android.permission.CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY"
-        android:permissionGroup="android.permission-group.ACCESSIBILITY_FEATURES"
-        android:label="@string/permlab_canRequestEnahncedWebAccessibility"
-        android:description="@string/permdesc_canRequestEnahncedWebAccessibility"
-        android:protectionLevel="dangerous" />
-
     <!-- ======================================= -->
     <!-- Permissions for accessing location info -->
     <!-- ======================================= -->
@@ -836,6 +824,7 @@
     <!-- ==================================================== -->
     <!-- Permissions related to changing audio settings   -->
     <!-- ==================================================== -->
+    <eat-comment />
 
     <!-- Used for permissions that provide direct access to speaker settings
          the device. -->
@@ -918,7 +907,8 @@
     <permission android:name="android.permission.RECORD_AUDIO"
         android:permissionGroup="android.permission-group.MICROPHONE"
         android:protectionLevel="dangerous"
-        android:label="@string/permlab_recordAudio" />
+        android:label="@string/permlab_recordAudio"
+        android:description="@string/permdesc_recordAudio" />
 
 
     <!-- =========================================== -->
@@ -1274,6 +1264,7 @@
     <!-- ==================================================== -->
     <!-- Permissions related to changing status bar   -->
     <!-- ==================================================== -->
+    <eat-comment />
 
     <!-- Used for permissions that change the status bar -->
     <permission-group android:name="android.permission-group.STATUS_BAR"
@@ -1292,6 +1283,7 @@
     <!-- ==================================================== -->
     <!-- Permissions related to accessing sync settings   -->
     <!-- ==================================================== -->
+    <eat-comment />
 
     <!-- Used for permissions that access the sync settings or sync
          related information. -->
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index ea194fc..f1119e2 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Herlaai"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Die bladsy by \"<xliff:g id="TITLE">%s</xliff:g>\" sê:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Navigeer weg van hierdie bladsy?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Raak OK om voort te gaan, of Kanselleer om op die huidige bladsy te bly."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Bevestig"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Wenk: Dubbeltik om in en uit te zoem."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Outovul"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 84eba57..d689022 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -387,7 +387,7 @@
     <string name="permdesc_clearAppCache" product="tablet" msgid="8974640871945434565">"በሌሎች መተግበሪያዎች የመሸጎጫ ማውጫዎች ውስጥ ያሉትን ፋይሎች በመሰረዝ መተግበሪያው የጡባዊ ማከማቻ ቦታ ነጻ እንዲያስለቅቅ ያስችለዋል። ይሄ ሌሎች መተግበሪያዎች ውሂባቸውን ዳግም ማምጣት ስላለባቸው ይበልጥ ዘግየት ብለው እንዲጀምሩ ሊያደርጋቸው ይችላል።"</string>
     <string name="permdesc_clearAppCache" product="default" msgid="2459441021956436779">"በሌሎች መተግበሪያዎች የመሸጎጫ ማውጫዎች ውስጥ ያሉትን ፋይሎች በመሰረዝ መተግበሪያው የስልክ ማከማቻ ቦታ ነጻ እንዲያስለቅቅ ያስችለዋል። ይሄ ሌሎች መተግበሪያዎች ውሂባቸውን ዳግም ማምጣት ስላለባቸው ይበልጥ ዘግየት ብለው እንዲጀምሩ ሊያደርጋቸው ይችላል።"</string>
     <string name="permlab_movePackage" msgid="3289890271645921411">"የመተግበሪያ ሃብቶችን አንቀሳቅስ"</string>
-    <string name="permdesc_movePackage" msgid="319562217778244524">"ከውስጣዊ ወደ  ውጫዊ ሚዲያ እና በተገላቢጦሽ የመተግበሪያ ሃብቶችን ለማንቀሳቀስ ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
+    <string name="permdesc_movePackage" msgid="319562217778244524">"ከውስጣዊ ወደ  ውጫዊ ማህደረ  መረጃ  እና በተገላቢጦሽ የመተግበሪያ ሃብቶችን ለማንቀሳቀስ ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
     <string name="permlab_readLogs" msgid="6615778543198967614">"ወሳኝ የማስታወሻ ውሂብ አንብብ"</string>
     <string name="permdesc_readLogs" product="tablet" msgid="82061313293455151">" ከስርዓቱ የተለያዩ የማስታወሻ ፋይሎች ውስጥ ለማንበብ ለመተግበሪያ ይፈቅዳሉ። ይህ ስለ ጡባዊ ተኮህ ምን እያደረክበት እንደሆነ የግላዊ  ወይም የግል መረጃን ጨምሮ ጠቅላላ መረጃ ለማግኘት ይፈቅዳል።"</string>
     <string name="permdesc_readLogs" product="default" msgid="2063438140241560443">" ከስርዓቱ የተለያዩ የማስታወሻ ፋይሎች ውስጥ ለማንበብ ለመተግበሪያይፈቅዳሉ። ይህ ስለ ስልክህ ምን እያደረክበት እንደሆነ የግላዊ  ወይም የግል መረጃን ጨምሮ ጠቅላላ መረጃ ለማግኘት ይፈቅዳል።"</string>
@@ -403,9 +403,9 @@
     <string name="permlab_setPreferredApplications" msgid="8463181628695396391">"ተመራጭ መተግበሪያዎች አዘጋጅ"</string>
     <string name="permdesc_setPreferredApplications" msgid="4973986762241783712">"ተመራጭ መተግበሪያዎችህን ለመቀየር ለመተግበሪያው ይፈቅዳሉ፡፡ ከአንተ የግል ውሂብ ለመሰብሰብ ያሉትን መተግበሪያዎች በመላክ፤ በመሄድ ላይ ያሉ መተግበሪያዎችን  ተንኮል አዘል መተግበሪያዎች በዝምታ ሊለውጡ ይችላሉ፡፡"</string>
     <string name="permlab_writeSettings" msgid="2226195290955224730">"የስርዓት ቅንብሮችን አስተካክል"</string>
-    <string name="permdesc_writeSettings" msgid="7775723441558907181">"የስርዓት ቅንጅቶችን ውሂብ ለመቀየር ለመተግበሪያው ይፈቅዳሉ፡፡ ተንኮል አዘል መተግበሪያዎች የስርዓትህን አወቃቀር ብልሹ ሊያደርጉት ይችላሉ፡፡"</string>
+    <string name="permdesc_writeSettings" msgid="7775723441558907181">"የስርዓት ቅንብሮችን ውሂብ ለመቀየር ለመተግበሪያው ይፈቅዳሉ። ተንኮል አዘል መተግበሪያዎች የስርዓትዎን አወቃቀር ብልሹ ሊያደርጉት ይችላሉ።"</string>
     <string name="permlab_writeSecureSettings" msgid="204676251876718288">"የስርዓት ቅንብሮችንደህንነት ቀይር"</string>
-    <string name="permdesc_writeSecureSettings" msgid="8159535613020137391">"የስርዓቱን ደህንነቱ የተጠበቀ ቅንጅቶችን ውሂብ ለመቀየር ለመተግበሪያው ይፈቅዳሉ፡፡ለመደበኛ ትግበራዎች  አያስፈልግም።"</string>
+    <string name="permdesc_writeSecureSettings" msgid="8159535613020137391">"የስርዓቱን ደህንነቱ የተጠበቀ ቅንብሮችን ውሂብ ለመቀየር ለመተግበሪያው ይፈቅዳሉ። ለመደበኛ ትግበራዎች አያስፈልግም።"</string>
     <string name="permlab_writeGservices" msgid="2149426664226152185">"የGoogle አገልግሎቶች ካርታን ቀይር"</string>
     <string name="permdesc_writeGservices" msgid="1287309437638380229">"ትግበራ የGoogle ካርታ አገልግሎቶችን ለመቀየር ይፈቅዳል።ለመደበኛ ትግበራዎች ጥቅም አይደለም።"</string>
     <string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"መነሻ ላይ አሂድ"</string>
@@ -541,8 +541,8 @@
     <string name="permlab_accountManagerService" msgid="4829262349691386986">"እንደ አውርድአዸራጅአገልግሎት"</string>
     <string name="permdesc_accountManagerService" msgid="1948455552333615954">" ወደ መለያ አረጋጋጮች ጥሪ ለማድረግ ለመተግበሪያ ይፈቅዳሉ።"</string>
     <string name="permlab_getAccounts" msgid="1086795467760122114">"መሣሪያው ላይ ያሉ መለያዎችን አግኝ"</string>
-    <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"መተግበሪያው በጡባዊ ተኮው የሚታወቁትን መለያዎች ዝርዝር እንዲያገኝ ይፈቅድለታል። ይህ በጫንካቸው ማናቸውም መተግበሪያዎች የተፈጠሩ መለያዎችን ሊያጠቃልል ይችላል።"</string>
-    <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"መተግበሪያው በስልኩ የሚታወቁትን መለያዎች ዝርዝር እንዲያገኝ ይፈቅድለታል። ይህ በጫንካቸው ማናቸውም መተግበሪያዎች የተፈጠሩ መለያዎችን ሊያጠቃልል ይችላል።"</string>
+    <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"መተግበሪያው በጡባዊ ተኮው የሚታወቁትን መለያዎች ዝርዝር እንዲያገኝ ይፈቅድለታል። ይህ በጫንዋቸው ማናቸውም መተግበሪያዎች የተፈጠሩ መለያዎችን ሊያጠቃልል ይችላል።"</string>
+    <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"መተግበሪያው በስልኩ የሚታወቁትን መለያዎች ዝርዝር እንዲያገኝ ይፈቅድለታል። ይህ በጫንዋቸው ማናቸውም መተግበሪያዎች የተፈጠሩ መለያዎችን ሊያጠቃልል ይችላል።"</string>
     <string name="permlab_authenticateAccounts" msgid="5265908481172736933">"መለያዎችን ፍጠርና የይለፍ ቃላትን አስቀምጥ"</string>
     <string name="permdesc_authenticateAccounts" msgid="5472124296908977260">"የመለያ አረጋጋጭ መለያ መናጅ ችሎታን ለመጠቀም፣ መለያ መፍጠር እና የይለፍ ቃሎችን ለማግኘት እና ለማቀናጀት አክሎ ለመተግበሪያው ይፈቅዳሉ ።"</string>
     <string name="permlab_manageAccounts" msgid="4983126304757177305">"መለያዎችን አክል ወይም አስወግድ"</string>
@@ -554,7 +554,7 @@
     <string name="permlab_createNetworkSockets" msgid="8018758136404323658">"ሙሉ የአውታረ መረብ መዳረሻ"</string>
     <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"መተግበሪያው የአውታረ መረብ መሰኪያዎችን እንዲፈጥር እና ብጁ የአውታረ መረብ ፕሮቶኮሎችን እንዲጠቀም ይፈቅድለታል። አሳሹ እና ሌሎች መተግበሪያዎች ውሂብ ወደ በይነመረብ የመላኪያ መንገዶችን ስለሚያቀርቡውሂብ ወደ በይነመረብ ለመላክ ይህ ፍቃድ አያስፈልግም።"</string>
     <string name="permlab_writeApnSettings" msgid="505660159675751896">"የአውታረ መረብ ቅንብሮች እና ትራፊክ ለውጥ/ አቋርጥ"</string>
-    <string name="permdesc_writeApnSettings" msgid="5333798886412714193">"የአውታረ መረብ ቅንጅቶችን ለመለወጥ እና ለማቋረጥ እና ሁሉንም የአውታረ መረብ ትራፊክ ለመመርመር፤ለምሳሌ ወኪል እና የማንኛውም APN ወደብ ለመለወጥ ለመተግበሪያው ይፈቅዳሉ፡፡ ተንኮል አዘል መተግበሪያዎች ሊቆጣጠሩ፣ አቅጣጫ ሊያስቀይሩ ፣ ወይም ያለአንተ እውቅና የአውታረ መረብ ፓኬቶችን ሊቀይሩ ይችላሉ፡፡"</string>
+    <string name="permdesc_writeApnSettings" msgid="5333798886412714193">"የአውታረ መረብ ቅንብሮችን ለመለወጥ እና ለማቋረጥ እና ሁሉንም የአውታረ መረብ ትራፊክ ለመመርመር፤ለምሳሌ ወኪል እና የማንኛውም APN ወደብ ለመለወጥ ለመተግበሪያው ይፈቅዳሉ። ተንኮል አዘል መተግበሪያዎች ሊቆጣጠሩ፣ አቅጣጫ ሊያስቀይሩ ፣ ወይም ያለእርስዎ እውቅና የአውታረ መረብ ፓኬቶችን ሊቀይሩ ይችላሉ።"</string>
     <string name="permlab_changeNetworkState" msgid="958884291454327309">"የአውታረ መረብ ተያያዥነትን ለውጥ"</string>
     <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"የእውታረ መረቡን ግንኙነት  ሁኔታ ለመለወጥ ለመተግበሪያው ይፈቅዳሉ።"</string>
     <string name="permlab_changeTetherState" msgid="5952584964373017960">"የተያያዘ ግንኙነት ለውጥ"</string>
@@ -601,7 +601,7 @@
     <string name="permlab_sdcardRead" product="default" msgid="8235341515605559677">"ጥበቃ ወደሚደረግለት ማከማቻ ያለ መዳረሻን ፈትሽ"</string>
     <string name="permdesc_sdcardRead" product="nosdcard" msgid="3642473292348132072">"መተግበሪያው በወደፊት መሳሪዎች ላይ ለሚኖር የUSB ማህደረ ትውስታ ፈቃድ እንዲሞክር ይፈቅድለታል።"</string>
     <string name="permdesc_sdcardRead" product="default" msgid="5914402684685848828">"መተግበሪያው በወደፊት መሳሪዎች ላይ ለሚኖረው SD ካርድ ፈቃድ እንዲሞክር ይፈቅድለታል።"</string>
-    <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"የUSB ማከማቻህን ይዘቶች ቀይር ወይም ሰርዝ"</string>
+    <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"የUSB ማከማቻዎን ይዘቶች ይቀይሩ ወይም ይሰርዙ"</string>
     <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"የSD ካርድህን ይዘቶች ቀይር ወይም ሰርዝ"</string>
     <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"ወደ USB ማህደረ ትውስታው ለመፃፍ ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"መተግበሪያውን ወደ SD ካርድ ለመፃፍ ይፈቅዳል።"</string>
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"ድጋሚ አስነሳ"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"በ«<xliff:g id="TITLE">%s</xliff:g>» ያለው ገጽ ይህን ይላል፦"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"ጃቫስክሪፕት"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"ከዚህ ገፅ ወጣ ብሎ ይዳስ? "\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n" ለመቀጠል እሺ ፣ወይም የአሁኑ ገፅ ላይ ለመቆየት ይቅር ምረጥ።"</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"አረጋግጥ"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"ጠቃሚ ምክር፦ ለማጉላት እና ለማሳነስ ሁለቴ-መታ አድርግ።"</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"ራስ ሙላ"</string>
@@ -1174,20 +1181,20 @@
     <string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff33b5e5">"አዲስ፦ "</font></string>
     <string name="perms_description_app" msgid="5139836143293299417">"በ<xliff:g id="APP_NAME">%1$s</xliff:g> የቀረበ።"</string>
     <string name="no_permissions" msgid="7283357728219338112">"ምንም ፍቃዶች አይጠየቁም"</string>
-    <string name="perm_costs_money" msgid="4902470324142151116">"ይህ ገንዘብ ሊያስወጣዎብዎት ይችላል"</string>
+    <string name="perm_costs_money" msgid="4902470324142151116">"ይህ ገንዘብ ሊያስወጣዎት ይችላል"</string>
     <string name="usb_storage_activity_title" msgid="4465055157209648641">"USB ብዙ ማከማቻ"</string>
     <string name="usb_storage_title" msgid="5901459041398751495">"USB ተያይዟል"</string>
     <string name="usb_storage_message" product="nosdcard" msgid="3308538094316477839">"ከኮምፒዩተርህ ጋር በUSB በኩል አገናኝተሃል። በኮምፒዩተርህ እና በAndroid SD ማከማቻህ መካከል ፋይሎች ለመቅዳት ከፈለግህ ከዚህ በታች ያለውን አዝራር ንካ።"</string>
     <string name="usb_storage_message" product="default" msgid="805351000446037811">"ከኮምፒዩተርህ ጋር በUSB በኩል አገናኝተሃል። በኮምፒዩተርህ እና በAndroid SD ማከማቻህ መካከል ፋይሎች ለመቅዳት ከፈለግህ ከዚህ በታች ያለውን አዝራር ንካ።"</string>
     <string name="usb_storage_button_mount" msgid="1052259930369508235">"የUSB ማከማቻ አብራ"</string>
-    <string name="usb_storage_error_message" product="nosdcard" msgid="3017045217365540658">"የUSB ማከማቻህን ለUSB ብዙማከማቻ መጠቀም ችግር አለ።"</string>
+    <string name="usb_storage_error_message" product="nosdcard" msgid="3017045217365540658">"የUSB ማከማቻዎን ለUSB ብዙ ማከማቻ መጠቀም ችግር አለ።"</string>
     <string name="usb_storage_error_message" product="default" msgid="2876018512716970313">"የ SD ካርድህን ለUSB ብዙማከማቻ መጠቀም ችግር አለ።"</string>
     <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB ተያይዟል"</string>
     <string name="usb_storage_notification_message" msgid="939822783828183763">"ፋይሎችን ከ/ወደ ኮምፒዩተርህ ለመቅዳት ንካ።"</string>
     <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"የUSB ማከማቻ አጥፋ"</string>
     <string name="usb_storage_stop_notification_message" msgid="1656852098555623822">"የUSB ማከማቻ ለማጥፋት ንካ።"</string>
     <string name="usb_storage_stop_title" msgid="660129851708775853">"USB ማከማቻ በጥቅም ላይ"</string>
-    <string name="usb_storage_stop_message" product="nosdcard" msgid="4264025280777219521">"USB ማከማቻን ከማጥፋትህ በፊት፤ የAndroid USB ማከማቻህን ከኮምውተርህ ንቀል (\"አውጣ\")።"</string>
+    <string name="usb_storage_stop_message" product="nosdcard" msgid="4264025280777219521">"USB ማከማቻን ከማጥፋትዎ በፊት፤ የAndroid USB ማከማቻዎን ከኮምውተርዎ ይንቀሉ (\"ያውጡ\")።"</string>
     <string name="usb_storage_stop_message" product="default" msgid="8043969782460613114">"የUSB ማከማቻ ከማጥፋት በፊት የAndroid SD ካርድህን ከኮምፒዩተርህ ላይ ንቀል(“አውጣ”)።"</string>
     <string name="usb_storage_stop_button_mount" msgid="7060218034900696029">"USB ማከማቻ አጥፋ"</string>
     <string name="usb_storage_stop_error_message" msgid="1970374898263063836">"የ USB ማከማቻ ለማጥፋት ችግር ነበር። USB አስተናጋጅ መንቀልህን አረጋግጥ፤ ከዛም እንደገና ሞክር።"</string>
@@ -1380,7 +1387,7 @@
     <string name="storage_usb" msgid="3017954059538517278">"የUSB  ማከማቻ"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"አርትዕ"</string>
     <string name="data_usage_warning_title" msgid="1955638862122232342">"የውሂብ አጠቃቀም ማስጠንቀቂየ"</string>
-    <string name="data_usage_warning_body" msgid="2814673551471969954">"ቅንጅቶችን እና አጠቃቀምን ለማየት ንካ።"</string>
+    <string name="data_usage_warning_body" msgid="2814673551471969954">"ቅንብሮችን እና አጠቃቀምን ለማየት ይንኩ።"</string>
     <string name="data_usage_3g_limit_title" msgid="7093334419518706686">"2G-3G ውሂብ ቦዝኗል"</string>
     <string name="data_usage_4g_limit_title" msgid="7636489436819470761">"4G ውሂብ ቦዝኗል"</string>
     <string name="data_usage_mobile_limit_title" msgid="7869402519391631884">"የተንቀሳቃሽ ውሂብ ቦዝኗል"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index d134ca4..0c611cd 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"إعادة تشغيل"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"تعرض الصفحة في \"<xliff:g id="TITLE">%s</xliff:g>\":"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"جافا سكريبت"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"هل تريد الانتقال بعيدًا عن هذه الصفحة؟"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"المس \"موافق\" للمتابعة، أو \"إلغاء\" للبقاء في الصفحة الحالية."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"تأكيد"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"نصيحة: اضغط مرتين للتكبير والتصغير."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"ملء تلقائي"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 9f3d3e6..eb2033c 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Перазагрузіць"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"На старонцы з адрасам <xliff:g id="TITLE">%s</xliff:g> вызначана:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Пакiнуць гэту старонку?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Націсніце \"OK\", каб працягнуць, або \"Адмена\", каб застацца на бягучай старонцы."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Пацвердзіць"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Падказка: двойчы націсніце, каб павялічыць або паменшыць."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Аўтазапаўненне"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 0983b5e..27a0f59 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Рестартиране"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Страницата на адрес „<xliff:g id="TITLE">%s</xliff:g>“ съобщава:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Искате ли да напуснете тази страница?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Докоснете „OK“, за да продължите, или „Отказ“, за да останете на нея."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Потвърждение"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Съвет: Докоснете двукратно, за да увеличите или намалите мащаба."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Автопоп."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index ccea866..4e68a6b 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Reinicia"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"La pàgina de \"<xliff:g id="TITLE">%s</xliff:g>\" diu:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Vols sortir d\'aquesta pàgina?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Selecciona D\'acord per continuar o Cancel·la per seguir a la pàgina actual."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Confirma"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Consell: Pica dos cops per ampliar i per reduir."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Em. aut."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index c9a84cb..c92d249 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -155,7 +155,7 @@
     <string name="global_action_lock" msgid="2844945191792119712">"Zámek obrazovky"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Vypnout"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Hlášení chyb"</string>
-    <string name="bugreport_title" msgid="2667494803742548533">"Zaznamenat zprávu o chybě"</string>
+    <string name="bugreport_title" msgid="2667494803742548533">"Vytvořit chybové hlášení"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Shromažďuje informace o aktuálním stavu zařízení. Tyto informace je následně možné poslat v e-mailové zprávě, chvíli však potrvá, než bude hlášení o chybě připraveno k odeslání. Buďte prosím trpěliví."</string>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Tichý režim"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Zvuk je VYPNUTÝ."</string>
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Restartovat"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Stránka <xliff:g id="TITLE">%s</xliff:g> uvádí:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Chcete opustit tuto stránku?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Chcete-li pokračovat, dotkněte se možnosti OK. Chcete-li zůstat na aktuální stránce, dotkněte se možnosti Zrušit."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Potvrdit"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tip: Dvojitým klepnutím můžete zobrazení přiblížit nebo oddálit."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Aut.vyp."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index d2b11e4..29a5776 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -156,7 +156,7 @@
     <string name="global_action_power_off" msgid="4471879440839879722">"Sluk"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Fejlrapport"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Lav fejlrapport"</string>
-    <string name="bugreport_message" msgid="398447048750350456">"Der indsamles oplysninger om din enheds aktuelle status, der efterfølgende sendes i en e-mail. Der går lidt tid, fra fejlrapporten påbegyndes, til den er klar til at blive sendt. Tak for tålmodigheden."</string>
+    <string name="bugreport_message" msgid="398447048750350456">"Der indsamles oplysninger om din enheds aktuelle status, der efterfølgende sendes i en e-mail. Der går lidt tid fra, at fejlrapporten påbegyndes, til den er klar til at blive sendt. Tak for tålmodigheden."</string>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Lydløs"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Lyden er slået FRA"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Lyden er TIL"</string>
@@ -622,7 +622,7 @@
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"adgang til underretninger"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Tillader, at appen kan hente, undersøge og rydde underretninger, herunder dem, der er sendt af andre apps."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"forpligte sig til en underretningslyttertjeneste"</string>
-    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Tillader, at brugeren kan forpligte sig til en grænseflade for en underretningslyttertjeneste på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string>
+    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Tillader brugeren at forpligte sig til en underretningslyttertjenestes grænseflade på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Indstil regler for adgangskode"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontroller længden samt tilladte tegn i adgangskoder til oplåsning af skærmen."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Overvåg forsøg på oplåsning af skærm"</string>
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Genstart"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"På siden på \"<xliff:g id="TITLE">%s</xliff:g>\" står der:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"Javascript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Vil du gå væk fra denne side?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Tryk på OK for at fortsætte eller Annuller for at blive på den aktuelle side."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Bekræft"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tip! Dobbeltklik for at zoome ind eller ud."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Autofyld"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index c03aa70..dcf27e3 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Neustart"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Auf der Seite \"<xliff:g id="TITLE">%s</xliff:g>\" steht:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Diese Seite verlassen?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Tippen Sie zum Fortfahren auf \"OK\" oder tippen Sie auf \"Abbrechen\", um auf der aktuellen Seite zu bleiben."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Bestätigen"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tipp: Zum Vergrößern und Verkleinern zweimal tippen"</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"AutoFill"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 6dcdbf1..414111d 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Επανεκκίνηση"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Η σελίδα στον τίτλο \"<xliff:g id="TITLE">%s</xliff:g>\" λέει:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Απομάκρυνση από αυτή τη σελίδα;"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Αγγίξτε το στοιχείο \"OK\" για συνέχεια ή \"Ακύρωση\" για παραμονή στην τρέχουσα σελίδα."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Επιβεβαίωση"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Συμβουλή: Πατήστε δύο φορές για μεγέθυνση και σμίκρυνση."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Αυτόματη συμπλήρωση"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 08283c4..d95c1d9 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Reboot"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"The page at \"<xliff:g id="TITLE">%s</xliff:g>\" says:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Navigate away from this page?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Touch OK to continue or Cancel to stay on the current page."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Confirm"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tip: double-tap to zoom in and out."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Auto-fill"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 98528f7..5005d41 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -773,7 +773,7 @@
     <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Presiona el Menú para desbloquear o realizar una llamada de emergencia."</string>
     <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Presionar Menú para desbloquear."</string>
     <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Dibujar el patrón de desbloqueo"</string>
-    <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Llamada de emergencia"</string>
+    <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Realizar llamada de emergencia"</string>
     <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Regresar a llamada"</string>
     <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Correcto"</string>
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Vuelve a intentarlo."</string>
@@ -783,7 +783,7 @@
     <string name="lockscreen_charged" msgid="321635745684060624">"Cargado"</string>
     <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
     <string name="lockscreen_low_battery" msgid="1482873981919249740">"Conecta tu cargador."</string>
-    <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"No hay tarjeta SIM."</string>
+    <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Sin tarjeta SIM"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"No hay tarjeta SIM en el tablet."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"No hay tarjeta SIM en el dispositivo."</string>
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Inserta una tarjeta SIM."</string>
@@ -795,7 +795,7 @@
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Botón Pausa"</string>
     <string name="lockscreen_transport_play_description" msgid="5888422938351019426">"Botón Reproducir"</string>
     <string name="lockscreen_transport_stop_description" msgid="4562318378766987601">"Botón Detener"</string>
-    <string name="emergency_calls_only" msgid="6733978304386365407">"Sólo llamadas de emergencia"</string>
+    <string name="emergency_calls_only" msgid="6733978304386365407">"Solo llamadas de emergencia"</string>
     <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Red bloqueada"</string>
     <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"La tarjeta SIM está bloqueada con PUK."</string>
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Consulta la guía del usuario o comunícate con el servicio de atención al cliente."</string>
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Reiniciar"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"La página \"<xliff:g id="TITLE">%s</xliff:g>\" dice:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"¿Deseas salir de esta página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Toca Aceptar para continuar o Cancelar para permanecer en la página actual."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Consejo: Toca dos veces para acercar y alejar la imagen."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Autocompletar"</string>
@@ -1437,7 +1444,7 @@
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Se conectó la pantalla inalámbrica"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Esta pantalla se muestra en otro dispositivo."</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Desconectar"</string>
-    <string name="kg_emergency_call_label" msgid="684946192523830531">"Llamada de emergencia"</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Realizar llamada de emergencia"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"¿Olvidaste el patrón?"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Patrón incorrecto"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Contraseña incorrecta"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 09acbe1..d20f7fa 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -559,8 +559,8 @@
     <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"Permite que la aplicación modifique el estado de la conectividad de red."</string>
     <string name="permlab_changeTetherState" msgid="5952584964373017960">"cambiar conectividad de anclaje a red"</string>
     <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Permite que la aplicación cambie el estado de la conectividad de red de anclaje."</string>
-    <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"cambiar configuración de uso de datos de referencia"</string>
-    <string name="permdesc_changeBackgroundDataSetting" msgid="5347729578468744379">"Permite que la aplicación cambie los ajustes de uso de datos de referencia."</string>
+    <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"cambiar configuración de uso de conexiones automáticas"</string>
+    <string name="permdesc_changeBackgroundDataSetting" msgid="5347729578468744379">"Permite que la aplicación cambie los ajustes de uso de conexiones automáticas."</string>
     <string name="permlab_accessWifiState" msgid="5202012949247040011">"ver conexiones Wi-Fi"</string>
     <string name="permdesc_accessWifiState" msgid="5002798077387803726">"Permite que la aplicación vea información sobre conexión a redes Wi-Fi (por ejemplo, si está habilitada la conexión Wi-Fi y el nombre de los dispositivos Wi-Fi conectados)."</string>
     <string name="permlab_changeWifiState" msgid="6550641188749128035">"conectarse a redes Wi-Fi y desconectarse"</string>
@@ -569,14 +569,14 @@
     <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"Permite que la aplicación reciba paquetes enviados a todos los dispositivos de una red Wi-Fi que utilicen direcciones de multidifusión, no solo al tablet. Utiliza más batería que el modo de no multidifusión."</string>
     <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Permite que la aplicación reciba paquetes enviados a todos los dispositivos de una red Wi-Fi que utilicen direcciones de multidifusión, no solo al teléfono. Utiliza más batería que el modo de no multidifusión."</string>
     <string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"acceder a los ajustes de Bluetooth"</string>
-    <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Permite que la aplicación configure el tablet Bluetooth local y que detecte dispositivos remotos y se sincronice con ellos."</string>
-    <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Permite que la aplicación configure el teléfono Bluetooth local y que detecte dispositivos remotos y se sincronice con ellos."</string>
+    <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Permite que la aplicación configure el tablet Bluetooth local y que detecte dispositivos remotos y se vincule con ellos."</string>
+    <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Permite que la aplicación configure el teléfono Bluetooth local y que detecte dispositivos remotos y se vincule con ellos."</string>
     <string name="permlab_accessWimaxState" msgid="4195907010610205703">"conectarse a WiMAX y desconectarse de esta red"</string>
     <string name="permdesc_accessWimaxState" msgid="6360102877261978887">"Permite que la aplicación determine si está habilitada la conexión WiMAX y obtenga información sobre las redes WiMAX que están conectadas."</string>
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Cambiar estado de WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permite que la aplicación conecte el tablet a redes WiMAX y lo desconecte de ellas."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permite que la aplicación conecte el teléfono a redes WiMAX y lo desconecte de ellas."</string>
-    <string name="permlab_bluetooth" msgid="6127769336339276828">"sincronizarse con dispositivos Bluetooth"</string>
+    <string name="permlab_bluetooth" msgid="6127769336339276828">"vincular con dispositivos Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permite que la aplicación acceda a la configuración de Bluetooth del tablet y que establezca y acepte conexiones con los dispositivos sincronizados."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permite que la aplicación acceda a la configuración de Bluetooth del teléfono y que establezca y acepte conexiones con los dispositivos sincronizados."</string>
     <string name="permlab_nfc" msgid="4423351274757876953">"controlar Comunicación de campo cercano (NFC)"</string>
@@ -702,7 +702,7 @@
     <string name="phoneTypeIsdn" msgid="8022453193171370337">"RDSI"</string>
     <string name="phoneTypeMain" msgid="6766137010628326916">"Principal"</string>
     <string name="phoneTypeOtherFax" msgid="8587657145072446565">"Otro fax"</string>
-    <string name="phoneTypeRadio" msgid="4093738079908667513">"Radio"</string>
+    <string name="phoneTypeRadio" msgid="4093738079908667513">"Señal móvil"</string>
     <string name="phoneTypeTelex" msgid="3367879952476250512">"Télex"</string>
     <string name="phoneTypeTtyTdd" msgid="8606514378585000044">"TTY TDD"</string>
     <string name="phoneTypeWorkMobile" msgid="1311426989184065709">"Móvil del trabajo"</string>
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Reiniciar"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"La página \"<xliff:g id="TITLE">%s</xliff:g>\" dice:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"¿Quieres salir de esta página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Toca Aceptar para continuar o Cancelar para permanecer en la página actual."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Sugerencia: toca dos veces para ampliar o reducir el contenido."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Autocompletar"</string>
@@ -1195,7 +1202,7 @@
     <string name="dlg_confirm_kill_storage_users_text" msgid="5100428757107469454">"Si activas el almacenamiento USB, se detendrán algunas aplicaciones que estás usando y es posible que no estén disponibles hasta que lo desactives."</string>
     <string name="dlg_error_title" msgid="7323658469626514207">"Error de funcionamiento de USB"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Aceptar"</string>
-    <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Conectado como disp. multimedia"</string>
+    <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Conectado como dispositivo multimedia"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Conectado como una cámara"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Conectado como instalador"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Conectado a un accesorio USB"</string>
@@ -1391,7 +1398,7 @@
     <string name="data_usage_mobile_limit_snoozed_title" msgid="279240572165412168">"Límite de datos móviles superado"</string>
     <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Límite de datos Wi-Fi superado"</string>
     <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"Límite superado en <xliff:g id="SIZE">%s</xliff:g>"</string>
-    <string name="data_usage_restricted_title" msgid="5965157361036321914">"Datos de referencia restringidos"</string>
+    <string name="data_usage_restricted_title" msgid="5965157361036321914">"Conexiones automáticas restringidas"</string>
     <string name="data_usage_restricted_body" msgid="6741521330997452990">"Toca para eliminar la restricción."</string>
     <string name="ssl_certificate" msgid="6510040486049237639">"Certificado de seguridad"</string>
     <string name="ssl_certificate_is_valid" msgid="6825263250774569373">"Este certificado es válido."</string>
@@ -1420,7 +1427,7 @@
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Teléfono"</string>
     <string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Auriculares"</string>
-    <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Altavoces del conector"</string>
+    <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Altavoces de la base"</string>
     <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index d2d4d63..c30e2a9 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Taaskäivita"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Leht  „<xliff:g id="TITLE">%s</xliff:g>” ütleb järgmist."</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Kas soovite sellelt lehelt lahkuda?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Jätkamiseks puudutage valikut OK, praegusele lehele jäämiseks valikut Tühista."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Kinnita"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Vihje: suurendamiseks ja vähendamiseks puudutage kaks korda."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Automaatne täitmine"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index f723c37..f254b52 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -622,7 +622,7 @@
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"اعلان‌های دسترسی"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"به برنامه اجازه می‌دهد به بازیابی، بررسی و پاک کردن اعلان‌ها از جمله موارد پست شده توسط سایر برنامه‌ها بپردازد."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"اتصال به یک سرویس شنونده اعلان"</string>
-    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"به دارنده اجازه می‌دهد به یک رابط سطح بالای سرویس شنونده اعلان متصل شود. این هرگز برای برنامه‌های عادی ضروری نیست."</string>
+    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"به دارنده اجازه می‌دهد به یک رابط سطح بالای سرویس شنونده اعلان متصل شود. هرگز نباید برای برنامه‌های عادی لازم شود."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"تنظیم قوانین رمز ورود"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"طول و نویسه‎های مجاز در گذرواژه‌های بازکردن قفل صفحه را کنترل کنید."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"نمایش تلاش‌های قفل گشایی صفحه"</string>
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"راه‌اندازی مجدد"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"صفحه در \"<xliff:g id="TITLE">%s</xliff:g>\" می‎گوید:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"جاوا اسکریپت"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"از این صفحه خارج می‎شوید؟"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"برای ادامه روی تأیید و برای ماندن در همین صفحه روی لغو کلیک کنید."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"تأیید"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"نکته: برای بزرگنمایی و کوچکنمایی، دو بار ضربه بزنید."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"تکمیل خودکار"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 7f7f07a..f75d474 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Käynnistä uudelleen"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Sivu <xliff:g id="TITLE">%s</xliff:g> sanoo:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Siirrytäänkö pois tältä sivulta?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Valitse OK, jos haluat jatkaa, tai Peruuta, jos et halua siirtyä pois sivulta."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Vahvista"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Vinkki: lähennä ja loitonna kaksoisnapauttamalla."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Aut. täyttö"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 65c4ce5..4a87fd0 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Redémarrer"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"La page \"<xliff:g id="TITLE">%s</xliff:g>\" indique :"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Voulez-vous quitter cette page ?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Appuyez sur \"OK\" pour continuer ou \"Annuler\" pour rester sur la page actuelle."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Confirmer"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Conseil : Appuyez deux fois pour faire un zoom avant ou arrière."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Saisie auto"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 79dbfff..b922e401 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"रीबूट करें"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"\'<xliff:g id="TITLE">%s</xliff:g>\' पर यह पृष्ठ दर्शाता है:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"इस पृष्ठ से दूर नेविगेट करें?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"जारी रखने के लिए ठीक को चुनें, या वर्तमान पृष्ठ पर रहने के लिए रद्द करें को चुनें."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"पुष्टि करें"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"युक्ति: ज़ूम इन और आउट करने के लिए डबल-टैप करें."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"स्‍वत: भरण"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 90b44d2..128b48c 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Ponovno pokreni"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Stranica na adresi \"<xliff:g id="TITLE">%s</xliff:g>\" sadrži sljedeće:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Želite otići s ove lokacije?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Za nastavak dodirnite U redu, a za ostanak na trenutačnoj stranici dodirnite Odustani."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Potvrdi"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Savjet: Dvaput dotaknite za povećavanje i smanjivanje."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Aut.pop."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index d71ac23..0e0f13a 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Újraindítás"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"A \"<xliff:g id="TITLE">%s</xliff:g>\" címen található oldal szerint:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Elhagyja ezt az oldalt?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"A folytatáshoz érintse meg az OK, a jelenlegi oldalon maradáshoz a Mégse lehetőséget."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Megerősítés"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tipp: érintse meg kétszer a nagyításhoz és kicsinyítéshez."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Kitöltés"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index a9b33de..fd04f2a 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Mulai ulang"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Laman pada \"<xliff:g id="TITLE">%s</xliff:g>\" menyatakan:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Beranjak dari laman ini?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Sentuh Oke untuk melanjutkan atau Batal untuk tetap pada laman ini."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Konfirmasi"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Kiat: Ketuk dua kali untuk memperbesar dan memperkecil."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Isiotomatis"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 560b049..7cda28a 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -440,16 +440,16 @@
     <string name="permlab_writeCalendar" msgid="8438874755193825647">"aggiunta o modifica di eventi di calendario e invio di email agli ospiti a insaputa dei proprietari"</string>
     <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"Consente all\'applicazione di aggiungere, rimuovere, modificare gli eventi che puoi modificare sul tablet, inclusi quelli di amici o colleghi. Ciò potrebbe consentire all\'applicazione di inviare messaggi apparentemente provenienti dai proprietari del calendario o di modificare eventi all\'insaputa dei proprietari."</string>
     <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"Consente all\'applicazione di aggiungere, rimuovere, modificare gli eventi che puoi modificare sul telefono, inclusi quelli di amici o colleghi. Ciò potrebbe consentire all\'applicazione di inviare messaggi apparentemente provenienti dai proprietari del calendario o di modificare eventi all\'insaputa dei proprietari."</string>
-    <string name="permlab_accessMockLocation" msgid="8688334974036823330">"fonti di localizzazione fittizie per test"</string>
-    <string name="permdesc_accessMockLocation" msgid="5808711039482051824">"Crea fonti di localizzazione fittizie per i test o installa un nuovo fornitore di posizione. Ciò consente all\'applicazione di ignorare la posizione e/o lo stato restituito da altre fonti di localizzazione, come il GPS o fornitori di posizione."</string>
+    <string name="permlab_accessMockLocation" msgid="8688334974036823330">"fonti di geolocalizzazione fittizie per test"</string>
+    <string name="permdesc_accessMockLocation" msgid="5808711039482051824">"Crea fonti di geolocalizzazione fittizie per i test o installa un nuovo fornitore di posizione. Ciò consente all\'applicazione di ignorare la posizione e/o lo stato restituito da altre fonti di geolocalizzazione, come il GPS o fornitori di posizione."</string>
     <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"accesso a comandi aggiuntivi del provider di localizz."</string>
-    <string name="permdesc_accessLocationExtraCommands" msgid="5945166642335800763">"Consente all\'applicazione di accedere a ulteriori comandi del fornitore di posizione. Ciò potrebbe consentire all\'applicazione di interferire con il funzionamento del GPS o di altre fonti di localizzazione."</string>
+    <string name="permdesc_accessLocationExtraCommands" msgid="5945166642335800763">"Consente all\'applicazione di accedere a ulteriori comandi del fornitore di posizione. Ciò potrebbe consentire all\'applicazione di interferire con il funzionamento del GPS o di altre fonti di geolocalizzazione."</string>
     <string name="permlab_installLocationProvider" msgid="6578101199825193873">"autorizzazione a installare un provider di localizzazione"</string>
-    <string name="permdesc_installLocationProvider" msgid="9066146120470591509">"Crea fonti di localizzazione fittizie per i test o installa un nuovo fornitore di posizione. Ciò consente all\'applicazione di ignorare la posizione e/o lo stato restituito da altre fonti di localizzazione, come il GPS o fornitori di posizione."</string>
+    <string name="permdesc_installLocationProvider" msgid="9066146120470591509">"Crea fonti di geolocalizzazione fittizie per i test o installa un nuovo fornitore di posizione. Ciò consente all\'applicazione di ignorare la posizione e/o lo stato restituito da altre fonti di geolocalizzazione, come il GPS o fornitori di posizione."</string>
     <string name="permlab_accessFineLocation" msgid="1191898061965273372">"posizione precisa (GPS e basata sulla rete)"</string>
-    <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Consente all\'applicazione di ottenere la tua posizione esatta utilizzando il sistema GPS (Global Positioning System) o fonti di localizzazione delle reti come ripetitori di telefonia mobile e Wi-Fi. Questi servizi di localizzazione devono essere attivi e disponibili sul dispositivo per poter essere utilizzati dall\'applicazione. Le applicazioni potrebbero utilizzare questa autorizzazione per stabilire la tua posizione e potrebbero consumare ulteriore batteria."</string>
+    <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Consente all\'applicazione di ottenere la tua posizione esatta utilizzando il sistema GPS (Global Positioning System) o fonti di geolocalizzazione delle reti come ripetitori di telefonia mobile e Wi-Fi. Questi servizi di localizzazione devono essere attivi e disponibili sul dispositivo per poter essere utilizzati dall\'applicazione. Le applicazioni potrebbero utilizzare questa autorizzazione per stabilire la tua posizione e potrebbero consumare ulteriore batteria."</string>
     <string name="permlab_accessCoarseLocation" msgid="4887895362354239628">"posizione approssimativa (basata sulla rete)"</string>
-    <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Consente all\'applicazione di ottenere la tua posizione approssimativa. Questa posizione viene ottenuta da servizi di localizzazione utilizzando fonti di localizzazione delle reti come ripetitori di telefonia mobile e Wi-Fi. Questi servizi di localizzazione devono essere attivi e disponibili sul dispositivo per poter essere utilizzati dall\'applicazione. Le applicazioni potrebbero utilizzare questa autorizzazione per stabilire la tua posizione approssimativa."</string>
+    <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Consente all\'applicazione di ottenere la tua posizione approssimativa. Questa posizione viene ottenuta da servizi di localizzazione utilizzando fonti di geolocalizzazione delle reti come ripetitori di telefonia mobile e Wi-Fi. Questi servizi di localizzazione devono essere attivi e disponibili sul dispositivo per poter essere utilizzati dall\'applicazione. Le applicazioni potrebbero utilizzare questa autorizzazione per stabilire la tua posizione approssimativa."</string>
     <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"accesso a SurfaceFlinger"</string>
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Consente all\'applicazione l\'utilizzo di funzioni di basso livello SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"lettura buffer di frame"</string>
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Riavvia"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"La pagina all\'indirizzo \"<xliff:g id="TITLE">%s</xliff:g>\" indica:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Uscire da questa pagina?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Tocca OK per continuare o Annulla per rimanere nella pagina corrente."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Conferma"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Suggerimento. Tocca due volte per aumentare e diminuire lo zoom."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Compilazione autom."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 42f0e2d..59b4f65 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"אתחל מחדש"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"בדף שבכתובת \'<xliff:g id="TITLE">%s</xliff:g>\' כתוב כך:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"לנווט אל מחוץ לדף זה?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"גע באפשרות \'אישור\' כדי להמשיך, או \'ביטול\' כדי להישאר בדף הנוכחי."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"אשר"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"טיפ: הקש פעמיים כדי להגדיל ולהקטין."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"מילוי אוטומטי"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index f6b93f9..4fafb60 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"再起動"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"<xliff:g id="TITLE">%s</xliff:g> のページ:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"このページから移動しますか?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"移動する場合は[OK]、現在のページに留まる場合は[キャンセル]をタップしてください。"</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"確認"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"ヒント: ダブルタップで拡大/縮小できます。"</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"自動入力"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 5f50ac4..df40880 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"다시 부팅"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"\'<xliff:g id="TITLE">%s</xliff:g>\' 페이지 내용:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"자바스크립트"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"다른 페이지를 탐색하시겠습니까?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"계속하려면 \'확인\'을 터치하고 현재 페이지에 그대로 있으려면 \'취소\'를 터치하세요."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"확인"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"도움말: 확대/축소하려면 두 번 탭합니다."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"자동완성"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 9237a2c..ed31762 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Pakartotinai įkelti"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Puslapyje šiuo adresu: <xliff:g id="TITLE">%s</xliff:g>, teigiama:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Išeiti iš šio puslapio?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Palieskite „Gerai“, jei norite tęsti, arba palieskite „Atšaukti“, jei norite likti dabartiniame puslapyje."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Patvirtinti"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Patarimas: palieskite dukart, kad padidintumėte ar sumažintumėte mastelį."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Automatinis pildymas"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 1de841e..3f30242 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Atsāknēt"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Lapā <xliff:g id="TITLE">%s</xliff:g> ir teikts:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Vai doties prom no šīs lapas?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Pieskarieties Labi, lai turpinātu, vai Atcelt, lai paliktu pašreizējā lapā."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Apstiprināt"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Padoms. Divreiz pieskarieties, lai tuvinātu un tālinātu."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Automātiskā aizpilde"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index af5b866..5f49ed3 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"But semula"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Halaman di \'<xliff:g id="TITLE">%s</xliff:g>\' berkata:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Navigasi keluar dari halaman ini?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Sentuh OK untuk meneruskan, atau Batal untuk terus berada di halaman semasa."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Sahkan"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Petua: Ketik dua kali untuk mengezum masuk dan keluar."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Auto isi"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index e0d9bf2..a81f017 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Omstart"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Siden på «<xliff:g id="TITLE">%s</xliff:g>» sier:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Vil du navigere bort fra denne siden?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Trykk på OK for å fortsette eller på Avbryt for å bli værende på siden."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Bekreft"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tips: Dobbelttrykk for å zoome inn og ut."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Autofyll"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 2e92761..0558096 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Opnieuw opstarten"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"De pagina op \'<xliff:g id="TITLE">%s</xliff:g>\' meldt het volgende:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Wilt u deze pagina verlaten?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Kies \'OK\' om door te gaan of \'Annuleren\' om op de huidige pagina te blijven."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Bevestigen"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tip: dubbeltik om in en uit te zoomen."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Autom. aanvullen"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index d8a4bf9..2fa77a9 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Uruchom ponownie"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Komunikat ze strony pod adresem „<xliff:g id="TITLE">%s</xliff:g>”:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Czy opuścić tę stronę?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Dotknij OK, aby kontynuować, lub Anuluj, aby pozostać na tej stronie."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Potwierdź"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Wskazówka: dotknij dwukrotnie, aby powiększyć lub pomniejszyć."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Autouzupełnianie"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 66d50e6..edb3414 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -144,7 +144,7 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Campainha ativada"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"A encerrar..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"O seu tablet irá encerrar."</string>
-    <string name="shutdown_confirm" product="default" msgid="649792175242821353">"O seu telefone irá encerrar."</string>
+    <string name="shutdown_confirm" product="default" msgid="649792175242821353">"O seu telefone será encerrado."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Pretende encerrar?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Reiniciar no modo de segurança"</string>
     <string name="reboot_safemode_confirm" msgid="55293944502784668">"Pretende reiniciar no modo de segurança? Se sim, irá desativar todas as aplicações de terceiros instaladas. Estas serão restauradas quando reiniciar novamente."</string>
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Reiniciar"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"A página em \"<xliff:g id="TITLE">%s</xliff:g>\" indica:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Navegar para outra página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Toque em OK para continuar ou Cancelar para permanecer na página atual."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Sugestão: toque duas vezes para aumentar ou diminuir o zoom."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Preenchimento Automático"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 3877158..184f704 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -160,9 +160,9 @@
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Modo silencioso"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Som DESATIVADO"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"O som está ATIVADO"</string>
-    <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo de avião"</string>
-    <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modo de avião ATIVADO"</string>
-    <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modo de avião DESATIVADO"</string>
+    <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo avião"</string>
+    <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modo avião ATIVADO"</string>
+    <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modo avião DESATIVADO"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt;999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Reiniciar"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"A página em \"<xliff:g id="TITLE">%s</xliff:g>\" diz:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Deseja sair desta página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Selecione OK para continuar ou Cancelar para permanecer na página atual."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Dica: toque duas vezes para aumentar e diminuir o zoom."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Preench. aut."</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index ba863cb..7d10377 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -1398,7 +1398,13 @@
     <!-- no translation found for js_dialog_title (1987483977834603872) -->
     <skip />
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <!-- no translation found for js_dialog_before_unload (730366588032430474) -->
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
     <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Confermar"</string>
     <!-- no translation found for double_tap_toast (4595046515400268881) -->
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 21fcf04..bad14405 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -622,7 +622,7 @@
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"accesare notificări"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite aplicației să recupereze, să examineze și să șteargă notificări, inclusiv pe cele postate de alte aplicații."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"conectare la un serviciu de citire a notificărilor"</string>
-    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu de citire a notificărilor. Nu ar trebui să fie niciodată necesară pentru aplicațiile obișnuite."</string>
+    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu de citire a notificărilor. În mod normal aplicațiile nu ar trebui să aibă nevoie de această permisiune."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Setaţi reguli pentru parolă"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Stabiliţi lungimea şi tipul de caractere permise în parolele pentru deblocarea ecranului."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizaţi încercările de deblocare a ecranului"</string>
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Reporniţi"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"La pagina de la „<xliff:g id="TITLE">%s</xliff:g>” apare:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Doriţi să părăsiţi această pagină?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Apăsaţi pe OK pentru a continua sau pe Anulaţi pentru a rămâne pe pagina curentă."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Confirmaţi"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Sfat: măriţi şi micşoraţi prin dublă atingere."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Automat"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 592271b..d9bf3e2 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Перезагрузка"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Подтвердите действие на <xliff:g id="TITLE">%s</xliff:g>"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Покинуть эту страницу?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Нажмите \"ОК\", чтобы продолжить, или \"Отмена\", чтобы остаться."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Подтвердите"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Совет: нажмите дважды, чтобы увеличить и уменьшить масштаб."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Автозаполнение"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 228a9e7..caedb22 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Reštartovať"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Stránka „<xliff:g id="TITLE">%s</xliff:g>“ uvádza:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Chcete opustiť túto stránku?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Ak chcete pokračovať, dotknite sa tlačidla OK. Ak chcete zostať na stránke, dotknite sa tlačidla Zrušiť."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Potvrdiť"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tip: Dvojitým klepnutím môžete zobrazenie priblížiť alebo oddialiť."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Aut.dop."</string>
@@ -1051,7 +1058,7 @@
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Nedostatok ukladacieho priestoru"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Niektoré systémové funkcie nemusia fungovať"</string>
     <string name="app_running_notification_title" msgid="8718335121060787914">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> je spustená"</string>
-    <string name="app_running_notification_text" msgid="4653586947747330058">"Dotknutím sa zobrazíte viac informácií alebo zastavíte aplikáciu."</string>
+    <string name="app_running_notification_text" msgid="4653586947747330058">"Dotykom si zobrazíte viac informácií alebo zastavíte aplikáciu."</string>
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Zrušiť"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 906c197..64df433 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Znova zaženi"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Na strani na »<xliff:g id="TITLE">%s</xliff:g>« piše:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Ali se želite premakniti s te strani"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Če želite nadaljevati, se dotaknite »V redu«, če želite ostati na trenutni strani, izberite »Prekliči«."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Potrdi"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Nasvet: Tapnite dvakrat, če želite povečati ali pomanjšati."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Samoizp."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 102ced6..ec0384c 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Поново покрени"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"На страници на адреси „<xliff:g id="TITLE">%s</xliff:g>“ пише следеће:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Желите ли да напустите ову страницу?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Додирните Потврди да бисте наставили или Откажи да бисте остали на тренутно отвореној страници."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Потврда"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Савет: Додирните двапут да бисте увећали и умањили приказ."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Аутом. поп."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index adeffc3..7993bf8 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Starta om"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"På sidan på <xliff:g id="TITLE">%s</xliff:g> står det:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Vill du lämna den här den här sidan?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Tryck på OK om du vill fortsätta eller på Avbryt om du vill vara kvar på den aktuella sidan."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Bekräfta"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tips! Dubbelknacka om du vill zooma in eller ut."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Autofyll"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 0c11321..535b805 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -138,7 +138,7 @@
     <string name="turn_on_radio" msgid="3912793092339962371">"Washa mtandao-hewa"</string>
     <string name="turn_off_radio" msgid="8198784949987062346">"Zima pasiwaya"</string>
     <string name="screen_lock" msgid="799094655496098153">"Funga skrini"</string>
-    <string name="power_off" msgid="4266614107412865048">"Nishati imezimwa"</string>
+    <string name="power_off" msgid="4266614107412865048">"Zima simu"</string>
     <string name="silent_mode_silent" msgid="319298163018473078">"Programu ya milio imezimwa"</string>
     <string name="silent_mode_vibrate" msgid="7072043388581551395">"Mtetemo wa programu ya milio"</string>
     <string name="silent_mode_ring" msgid="8592241816194074353">"Programu ya milio imewashwa"</string>
@@ -153,7 +153,7 @@
     <string name="global_actions" product="tablet" msgid="408477140088053665">"Chaguo za kompyuta ndogo"</string>
     <string name="global_actions" product="default" msgid="2406416831541615258">"Chaguo za simu"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Funga skrini"</string>
-    <string name="global_action_power_off" msgid="4471879440839879722">"Nishati imezimwa"</string>
+    <string name="global_action_power_off" msgid="4471879440839879722">"Zima simu"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Ripoti ya hitilafu"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Chukua ripoti ya hitilafu"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Hii itakusanya maelezo kuhusu hali yako ya sasa ya kifaa, ili kutuma ujumbe wa barua pepe. Itachukua muda mfupi kuanza ripoti ya hitilafu mpaka itakapokuwa tayari kutumwa; tafadhali vumilia."</string>
@@ -519,7 +519,7 @@
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"zuia simu dhidi ya kulala"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Inaruhusu programu kuzuia kompyuta kibao  kwenda kulala."</string>
     <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Inaruhusu programu kuzuia simu isiende kulala."</string>
-    <string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"Washa au zima kompyuta ndogo"</string>
+    <string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"Washa au zima kompyuta kibao"</string>
     <string name="permlab_devicePower" product="default" msgid="4928622470980943206">"washa au zima simu"</string>
     <string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Inaruhusu programu kuwasha au kuzima kompyuta kibao."</string>
     <string name="permdesc_devicePower" product="default" msgid="6037057348463131032">"Inaruhusu programu kuwasha au kuzima simu."</string>
@@ -622,7 +622,7 @@
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"fikia arifa"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Huruhusu programu kurejesha, kuchunguza, na kuondoa arifa, ikiwa ni pamoja na zile zilizochapishwa na programu nyingine."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"unganisha kwenye huduma ya kisikilizi cha arifa"</string>
-    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Inaruhusu kishikilizi kuunganishwa kwenye kiolesura cha kiwango cha juu cha huduma ya kisikilizi cha arifa. Haipaswi kuhitajika tena kwa programu za kawaida."</string>
+    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Inaruhusu kishikilizi kuunganishwa kwenye kusano cha kiwango cha juu cha huduma ya kisikilizi cha arifa. Haipaswi kuhitajika tena kwa programu za kawaida."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Weka kanuni za nenosiri"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Dhibiti urefu na vibambo vinavyoruhusiwa katika manenosiri ya kufungua skrini."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Chunguza majaribio ya kutofun gua skrini"</string>
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Washa tena"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Ukurasa ulio \"<xliff:g id="TITLE">%s</xliff:g>\" unasema:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"HatiJava"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Toka kwa ukurasa huu?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Gusa Sawa ili kuendelea, au Ghairi ili kubaki kwenye ukurasa wa sasa."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Thibitisha"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Kidokezo: Gonga mara mbili ili kukuza ndani na nje."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Kujaza kiotomatiki"</string>
@@ -1060,7 +1067,7 @@
     <string name="loading" msgid="7933681260296021180">"Inapakia…"</string>
     <string name="capital_on" msgid="1544682755514494298">"Washa"</string>
     <string name="capital_off" msgid="6815870386972805832">"ZIMA"</string>
-    <string name="whichApplication" msgid="4533185947064773386">"Kamilisha kitendo kwa kutumia"</string>
+    <string name="whichApplication" msgid="4533185947064773386">"Kamilisha kitendo ukitumia"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Tumia kama chaguo-msingi la kitendo hiki."</string>
     <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Futa chaguo-msingi katika mipangilio ya Mfumo &gt; Apps &gt; iliyopakuliwa."</string>
     <string name="chooseActivity" msgid="7486876147751803333">"Chagua kitendo"</string>
@@ -1284,7 +1291,7 @@
     <string name="submit" msgid="1602335572089911941">"Wasilisha"</string>
     <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Mtindo wa gari umewezeshwa"</string>
     <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"Gusa ili kutoka katika modi ya gari."</string>
-    <string name="tethered_notification_title" msgid="3146694234398202601">"Amilisha uzuiaji au mahali maalum"</string>
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Kushiriki au kusambaza intaneti kumewashwa"</string>
     <string name="tethered_notification_message" msgid="6857031760103062982">"Gusa ili kusanidi."</string>
     <string name="back_button_label" msgid="2300470004503343439">"Nyuma"</string>
     <string name="next_button_label" msgid="1080555104677992408">"Ifuatayo"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index a92db72..1c97cb0d 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"รีบูต"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"หน้าเว็บที่ \"<xliff:g id="TITLE">%s</xliff:g>\" ระบุว่า:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"ไปจากหน้าเว็บนี้หรือไม่"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"แตะ \"ตกลง\" เพื่อทำต่อ หรือ \"ยกเลิก\" เพื่ออยู่ที่หน้าเว็บปัจจุบัน"</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"ยืนยัน"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"เคล็ดลับ: แตะสองครั้งเพื่อขยายและย่อ"</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"ป้อนอัตโนมัติ"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index e726333..45a5410 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"I-reboot"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Isinasaad ng pahina sa \"<xliff:g id="TITLE">%s</xliff:g>\" na:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Mag-navigate palayo mula sa pahinang ito?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Pindutin ang OK upang magpatuloy, o Kanselahin upang manatili sa kasalukuyang pahina."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Kumpirmahin"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tip: Mag-double tap upang mag-zoom in at out."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Autofill"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 9e5e43b..77b1cc6 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Yeniden başlat"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"\"<xliff:g id="TITLE">%s</xliff:g>\" adresindeki sayfada şunlar belirtiliyor:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Bu sayfadan ayrılıyor musunuz?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Devam etmek için Tamam\'ı, mevcut sayfada kalmak için İptal\'i tıklayın."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Onayla"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"İpucu: Yakınlaştırmak ve uzaklaştırmak için iki kez hafifçe vurun."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Otomatik Doldur"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index bb223ea..0cdedc1 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Перезав."</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"На сторінці за адресою \"<xliff:g id="TITLE">%s</xliff:g>\" написано:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"Javascript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Перейти з цієї сторінки?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Торкніться \"OK\", щоб продовжити, або \"Скасувати\", щоб залишитися на поточній сторінці."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Підтверд."</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Порада: двічі торкніться для збільшення чи зменшення."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Автозап."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index a592144..7732f4a 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Khởi động lại"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Trang tại \"<xliff:g id="TITLE">%s</xliff:g>\" cho biết:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Điều hướng khỏi trang này?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Chạm OK để tiếp tục hoặc Hủy để ở lại trang hiện tại."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Xác nhận"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Mẹo: Nhấn đúp để phóng to và thu nhỏ."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Tự động điền"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 79c79f3..9d1c48c 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"重新启动"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"网址为“<xliff:g id="TITLE">%s</xliff:g>”的网页显示:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"要从此页面导航至其他页面吗?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"触摸“确定”继续,或触摸“取消”留在当前页面。"</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"确认"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"提示:点按两次可放大或缩小。"</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"自动填充"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index dfd91a4..b4c41b4 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"重新開機"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"「<xliff:g id="TITLE">%s</xliff:g>」網頁指出:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"離開這個頁面?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"輕觸 [確定] 離開這個頁面,或輕觸 [取消] 停留在這個頁面。"</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"確認"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"提示:輕按兩下即可縮放。"</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"自動填入功能"</string>
@@ -1475,7 +1482,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您的解鎖圖形已畫錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,系統就會要求您透過電子郵件帳戶解除手機的鎖定狀態。"\n\n"請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後再試一次。"</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"移除"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"要將音量調高到建議等級以上嗎?"\n"長時間聆聽偏高音量可能會損害您的聽力。"</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"要將音量調高到建議等級以上嗎?"\n"長時間聆聽高音量可能會損害您的聽力。"</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"持續用兩指按住即可啟用協助工具。"</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"協助工具已啟用。"</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"協助工具已取消。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 41ac207..e2f1478 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Qalisa kabusha"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Ikhasi eliku <xliff:g id="TITLE">%s</xliff:g> lithi:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"i-JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Phuma kuleli khasi? "\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n" Thinta KULUNGILE ukuqhubeka, noma Khansela ukuhlala kuleli khasi."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Qinisekisa"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Ithiphu: thepha kabili ukusondeza ngaphandle nangaphakathi."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Ukugcwalisa Ngokuzenzakalelayo"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 8c7a374..60f3f32 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2521,13 +2521,43 @@
             <flag name="flagRequestTouchExplorationMode" value="0x00000004" />
             <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY} -->
             <flag name="flagRequestEnhancedWebAccessibility" value="0x00000008" />
+            <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS} -->
+            <flag name="flagReportViewIds" value="0x00000010" />
+            <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_FILTER_KEY_EVENTS} -->
+            <flag name="flagRequestFilterKeyEvents" value="0x00000020" />
         </attr>
         <!-- Component name of an activity that allows the user to modify
              the settings for this service. This setting cannot be changed at runtime. -->
         <attr name="settingsActivity" />
-        <!-- Flag whether the accessibility service wants to be able to retrieve the
+        <!-- Attribute whether the accessibility service wants to be able to retrieve the
              active window content. This setting cannot be changed at runtime. -->
         <attr name="canRetrieveWindowContent" format="boolean" />
+        <!-- Attribute whether the accessibility service wants to be able to request touch
+             exploration mode in which touched items are spoken aloud and the UI can be
+             explored via gestures.
+             <p>
+             Required to allow setting the {@link android.accessibilityservice
+             #AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} flag.
+             </p>
+         -->
+        <attr name="canRequestTouchExplorationMode" format="boolean" />
+        <!-- Attribute whether the accessibility service wants to be able to request enhanced
+             web accessibility enhancements. For example, installing scripts to make app
+             content more accessible.
+             <p>
+             Required to allow setting the {@link android.accessibilityservice
+             #AccessibilityServiceInfo#FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY} flag.
+             </p>
+         -->
+        <attr name="canRequestEnhancedWebAccessibility" format="boolean" />
+        <!-- Attribute whether the accessibility service wants to be able to request to
+             filter key events.
+             <p>
+             Required to allow setting the {@link android.accessibilityservice
+             #AccessibilityServiceInfo#FLAG_REQUEST_FILTER_KEY_EVENTS} flag.
+             </p>
+         -->
+        <attr name="canRequestFilterKeyEvents" format="boolean" />
         <!-- Short description of the accessibility serivce purpose or behavior.-->
         <attr name="description" />
     </declare-styleable>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 8821a01..f2c0aa0 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/config.xml b/core/res/res/values/config.xml
index cc50d8a..84e300a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -345,6 +345,12 @@
          A value of -1 means no change in orientation by default. -->
     <integer name="config_carDockRotation">-1</integer>
 
+    <!-- The number of degrees to rotate the display when the device has HDMI connected
+         but is not in a dock.  A value of -1 means no change in orientation by default.
+         Use -1 except on older devices whose Hardware Composer HAL does not
+         provide full support for multiple displays.  -->
+    <integer name="config_undockedHdmiRotation">-1</integer>
+
     <!-- Control the default UI mode type to use when there is no other type override
          happening.  One of the following values (See Configuration.java):
              1  UI_MODE_TYPE_NORMAL
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 074d91f..c150fe0 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2043,10 +2043,10 @@
   <public type="attr" name="childIndicatorEnd" />
   <public type="attr" name="restrictedAccountType" />
   <public type="attr" name="requiredAccountType" />
+  <public type="attr" name="canRequestTouchExplorationMode" />
+  <public type="attr" name="canRequestEnhancedWebAccessibility" />
+  <public type="attr" name="canRequestFilterKeyEvents" />
 
-  <public type="style" name="Theme.NoTitleBar.Overscan" />
-  <public type="style" name="Theme.Light.NoTitleBar.Overscan" />
-  <public type="style" name="Theme.Black.NoTitleBar.Overscan" />
   <public type="style" name="Theme.Holo.NoActionBar.Overscan" />
   <public type="style" name="Theme.Holo.Light.NoActionBar.Overscan" />
   <public type="style" name="Theme.DeviceDefault.NoActionBar.Overscan" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a0e1603..db9602a 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -545,6 +545,31 @@
     <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgroupdesc_accessibilityFeatures">Features that assistive technology can request.</string>
 
+    <!-- Title for the capability of an accessibility service to retrieve window content. -->
+    <string name="capability_title_canRetrieveWindowContent">Retrieve window content</string>
+    <!-- Description for the capability of an accessibility service to retrieve window content. -->
+    <string name="capability_desc_canRetrieveWindowContent">Inspect the content of a window you\'re
+        interacting with.</string>
+
+    <!-- Title for the capability of an accessibility service to request touch exploration. -->
+    <string name="capability_title_canRequestTouchExploration">Turn on Explore by Touch</string>
+    <!-- Description for the capability of an accessibility service to request touch exploration. -->
+    <string name="capability_desc_canRequestTouchExploration">Touched items will be spoken aloud
+        and the screen can be explored using gestures.</string>
+
+    <!-- Title for the capability of an accessibility service to request enhanced web accessibility. -->
+    <string name="capability_title_canRequestEnhancedWebAccessibility">Turn on enhanced web
+        accessibility</string>
+    <!-- Description for the capability of an accessibility service to request enhanced web accessibility. -->
+    <string name="capability_desc_canRequestEnhancedWebAccessibility">Scripts may be installed to
+        make app content more accessible.</string>
+
+    <!-- Title for the capability of an accessibility service to request to filter key events. -->
+    <string name="capability_title_canRequestFilterKeyEvents">Observe text you type</string>
+    <!-- Description for the capability of an accessibility service to request to filter key events. -->
+    <string name="capability_desc_canRequestFilterKeyEvents">Includes personal data such as credit
+        card numbers and passwords.</string>
+
     <!--  Permissions -->
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -945,20 +970,6 @@
         interface of an accessibility service. Should never be needed for normal apps.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_canRequestTouchExplorationMode">request explore by touch</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_canRequestTouchExplorationMode">Allows the hoder to request an
-        interaction mode in which touched items are spoken aloud and the UI can be explored
-        via gestures.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_canRequestEnahncedWebAccessibility">request enhanced web accessibility</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_canRequestEnahncedWebAccessibility">Allows the hoder to request
-        enabling of web accessibility enhancements. For example, installing scripts to make
-        app content more accessible.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_bindTextService">bind to a text service</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_bindTextService">Allows the holder to bind to the top-level
@@ -2411,9 +2422,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 e06bcd1..fdf7c8f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -438,6 +438,14 @@
   <java-symbol type="string" name="badPin" />
   <java-symbol type="string" name="badPuk" />
   <java-symbol type="string" name="byteShort" />
+  <java-symbol type="string" name="capability_desc_canRequestEnhancedWebAccessibility" />
+  <java-symbol type="string" name="capability_title_canRequestFilterKeyEvents" />
+  <java-symbol type="string" name="capability_desc_canRequestTouchExploration" />
+  <java-symbol type="string" name="capability_desc_canRetrieveWindowContent" />
+  <java-symbol type="string" name="capability_title_canRequestEnhancedWebAccessibility" />
+  <java-symbol type="string" name="capability_desc_canRequestFilterKeyEvents" />
+  <java-symbol type="string" name="capability_title_canRequestTouchExploration" />
+  <java-symbol type="string" name="capability_title_canRetrieveWindowContent" />
   <java-symbol type="string" name="cfTemplateForwarded" />
   <java-symbol type="string" name="cfTemplateForwardedTime" />
   <java-symbol type="string" name="cfTemplateNotForwarded" />
@@ -549,6 +557,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" />
@@ -1581,6 +1592,7 @@
   <java-symbol type="integer" name="config_screenBrightnessSettingDefault" />
   <java-symbol type="integer" name="config_screenBrightnessDim" />
   <java-symbol type="integer" name="config_shutdownBatteryTemperature" />
+  <java-symbol type="integer" name="config_undockedHdmiRotation" />
   <java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" />
   <java-symbol type="layout" name="am_compat_mode_dialog" />
   <java-symbol type="layout" name="launch_warning" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index e1750af..80f7486 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -405,16 +405,6 @@
         <item name="android:windowContentOverlay">@null</item>
     </style>
     
-    <!-- Variant of {@link #Theme} that has no title bar and no status bar and extending
-        into the display overscan region.  This theme
-        sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
-        to true. -->
-    <style name="Theme.NoTitleBar.Overscan">
-        <item name="android:windowFullscreen">true</item>
-        <item name="android:windowOverscan">true</item>
-        <item name="android:windowContentOverlay">@null</item>
-    </style>
-
     <!-- Theme for a light background with dark text on top.  Set your activity
          to this theme if you would like such an appearance.  As with the
          default theme, you should try to assume little more than that the
@@ -508,16 +498,6 @@
         <item name="android:windowContentOverlay">@null</item>
     </style>
     
-    <!-- Variant of {@link #Theme_Light} that has no title bar and
-         no status bar and extending into the display overscan region.  This theme
-         sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
-         to true. -->
-    <style name="Theme.Light.NoTitleBar.Overscan">
-        <item name="android:windowFullscreen">true</item>
-        <item name="android:windowOverscan">true</item>
-        <item name="android:windowContentOverlay">@null</item>
-    </style>
-
     <!-- Variant on {@link #Theme} that ensures the background is
          completely black.  This is useful for things like image viewers and
          media players.   If you want the normal (dark background) theme
@@ -539,16 +519,6 @@
         <item name="android:windowFullscreen">true</item>
         <item name="android:windowContentOverlay">@null</item>
     </style>
-    
-    <!-- Variant of {@link #Theme_Black} that has no title bar and
-         no status bar and extending into the display overscan region.  This theme
-         sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
-         to true. -->
-    <style name="Theme.Black.NoTitleBar.Overscan">
-        <item name="android:windowFullscreen">true</item>
-        <item name="android:windowOverscan">true</item>
-        <item name="android:windowContentOverlay">@null</item>
-    </style>
 
     <!-- Theme for windows that want to have the user's selected
          wallpaper appear behind them (for API level 10 and lower).  -->
diff --git a/data/keyboards/Vendor_0079_Product_0011.kl b/data/keyboards/Vendor_0079_Product_0011.kl
new file mode 100644
index 0000000..2ae2a01
--- /dev/null
+++ b/data/keyboards/Vendor_0079_Product_0011.kl
@@ -0,0 +1,23 @@
+# 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.
+
+# Classic NES Controller
+
+key 289 BUTTON_A
+key 290 BUTTON_B
+key 297 BUTTON_START
+key 296 BUTTON_SELECT
+
+axis 0x00 HAT_X
+axis 0x01 HAT_Y
diff --git a/data/keyboards/Vendor_045e_Product_028e.kl b/data/keyboards/Vendor_045e_Product_028e.kl
index 99f046a..ca6fa59 100644
--- a/data/keyboards/Vendor_045e_Product_028e.kl
+++ b/data/keyboards/Vendor_045e_Product_028e.kl
@@ -22,9 +22,9 @@
 key 308   BUTTON_Y
 key 310   BUTTON_L1
 key 311   BUTTON_R1
-key 314   BUTTON_SELECT
+key 314   BUTTON_BACK
 key 315   BUTTON_START
-key 316   BUTTON_MODE
+key 316   BUTTON_HOME
 key 317   BUTTON_THUMBL
 key 318   BUTTON_THUMBR
 
diff --git a/data/keyboards/Vendor_046d_Product_c219.kl b/data/keyboards/Vendor_046d_Product_c219.kl
new file mode 100644
index 0000000..431dd03
--- /dev/null
+++ b/data/keyboards/Vendor_046d_Product_c219.kl
@@ -0,0 +1,35 @@
+# 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.
+
+# Logitech Logitech Cordless RumblePad 2
+
+key 305 BUTTON_A
+key 306 BUTTON_B
+key 304 BUTTON_X
+key 307 BUTTON_Y
+key 308 BUTTON_L1
+key 309 BUTTON_R1
+key 310 BUTTON_L2
+key 311 BUTTON_R2
+key 313 BUTTON_START
+key 312 BUTTON_BACK
+key 314 BUTTON_THUMBL
+key 315 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x02 Z
+axis 0x05 RZ
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_046d_Product_c21f.kl b/data/keyboards/Vendor_046d_Product_c21f.kl
new file mode 100644
index 0000000..981d864
--- /dev/null
+++ b/data/keyboards/Vendor_046d_Product_c21f.kl
@@ -0,0 +1,36 @@
+# 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.
+
+# Logitech Wireless Gamepad F710
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 316 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_054c_Product_0268.kl b/data/keyboards/Vendor_054c_Product_0268.kl
index f8ac6a3..62c5f4d5 100644
--- a/data/keyboards/Vendor_054c_Product_0268.kl
+++ b/data/keyboards/Vendor_054c_Product_0268.kl
@@ -23,10 +23,10 @@
 
 key 0x120    BUTTON_SELECT
 key 0x123    BUTTON_START
-key 0x12f    BUTTON_A
-key 0x12c    BUTTON_B
-key 0x12e    BUTTON_X
-key 0x12d    BUTTON_Y
+key 0x12e    BUTTON_A
+key 0x12d    BUTTON_B
+key 0x12f    BUTTON_X
+key 0x12c    BUTTON_Y
 key 0x12a    BUTTON_L1
 key 0x12b    BUTTON_R1
 key 0x128    BUTTON_L2
@@ -35,7 +35,7 @@
 key 0x122    BUTTON_THUMBR
 
 # PS key
-key 0x2d0    BUTTON_1
+key 0x2d0    BUTTON_HOME
 
 # Left Analog Stick
 axis 0x00    X
diff --git a/data/keyboards/Vendor_0583_Product_2060.kl b/data/keyboards/Vendor_0583_Product_2060.kl
new file mode 100644
index 0000000..92c8a14
--- /dev/null
+++ b/data/keyboards/Vendor_0583_Product_2060.kl
@@ -0,0 +1,27 @@
+# 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.
+
+# ION GO PAD
+
+key 288 BUTTON_A
+key 289 BUTTON_B
+key 290 BUTTON_X
+key 291 BUTTON_Y
+key 294 BUTTON_L1
+key 295 BUTTON_R1
+key 292 BUTTON_L2
+key 293 BUTTON_R2
+
+axis 0x00 HAT_X
+axis 0x01 HAT_Y
diff --git a/data/keyboards/Vendor_0a5c_Product_8502.kl b/data/keyboards/Vendor_0a5c_Product_8502.kl
new file mode 100644
index 0000000..0084969
--- /dev/null
+++ b/data/keyboards/Vendor_0a5c_Product_8502.kl
@@ -0,0 +1,33 @@
+# 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.
+
+# Snakebyte
+
+key 289 BUTTON_A
+key 290 BUTTON_B
+key 288 BUTTON_X
+key 291 BUTTON_Y
+key 292 BUTTON_L1
+key 293 BUTTON_R1
+key 294 BUTTON_L2
+key 295 BUTTON_R2
+key 297 BUTTON_START
+key 296 BUTTON_SELECT
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x02 Z
+axis 0x05 RZ
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_1038_Product_1412.kl b/data/keyboards/Vendor_1038_Product_1412.kl
new file mode 100644
index 0000000..551b0bd
--- /dev/null
+++ b/data/keyboards/Vendor_1038_Product_1412.kl
@@ -0,0 +1,31 @@
+# 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.
+
+# Steelseries Free
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 316 BUTTON_SELECT
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x02 Z
+axis 0x05 RZ
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_12bd_Product_d015.kl b/data/keyboards/Vendor_12bd_Product_d015.kl
new file mode 100644
index 0000000..557d62f
--- /dev/null
+++ b/data/keyboards/Vendor_12bd_Product_d015.kl
@@ -0,0 +1,27 @@
+# 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.
+
+# Hitgaming SNES Retro
+
+key 306 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 304 BUTTON_Y
+key 308 BUTTON_L1
+key 309 BUTTON_R1
+key 313 BUTTON_START
+key 312 BUTTON_SELECT
+
+axis 0x00 HAT_X
+axis 0x01 HAT_Y
diff --git a/data/keyboards/Vendor_1689_Product_fd00.kl b/data/keyboards/Vendor_1689_Product_fd00.kl
new file mode 100644
index 0000000..6ce14ed
--- /dev/null
+++ b/data/keyboards/Vendor_1689_Product_fd00.kl
@@ -0,0 +1,38 @@
+# 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.
+
+# Razer Onza Tournament Edition
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 307 BUTTON_L1
+key 308 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 316 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+key 706 DPAD_UP
+key 705 DPAD_RIGHT
+key 707 DPAD_DOWN
+key 704 DPAD_LEFT
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
diff --git a/data/keyboards/Vendor_1689_Product_fd01.kl b/data/keyboards/Vendor_1689_Product_fd01.kl
new file mode 100644
index 0000000..8144515
--- /dev/null
+++ b/data/keyboards/Vendor_1689_Product_fd01.kl
@@ -0,0 +1,36 @@
+# 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.
+
+# Razer Xbox 360 Gamepad
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 308 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 316 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_1689_Product_fe00.kl b/data/keyboards/Vendor_1689_Product_fe00.kl
new file mode 100644
index 0000000..90fe4af
--- /dev/null
+++ b/data/keyboards/Vendor_1689_Product_fe00.kl
@@ -0,0 +1,36 @@
+# 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.
+
+# Razer Sabertooth Elite
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 316 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_1bad_Product_f016.kl b/data/keyboards/Vendor_1bad_Product_f016.kl
new file mode 100644
index 0000000..b72fd5ce
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_f016.kl
@@ -0,0 +1,36 @@
+# 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.
+
+# Madcatz Gamepad
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 316 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_1bad_Product_f023.kl b/data/keyboards/Vendor_1bad_Product_f023.kl
new file mode 100644
index 0000000..c1588b2
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_f023.kl
@@ -0,0 +1,35 @@
+# 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.
+
+# Mad Catz MLG GamePad for Xbox 360
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_1bad_Product_f027.kl b/data/keyboards/Vendor_1bad_Product_f027.kl
new file mode 100644
index 0000000..ea0aa7a
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_f027.kl
@@ -0,0 +1,36 @@
+# 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.
+
+# MadCatz FPS Pro
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 316 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_1bad_Product_f036.kl b/data/keyboards/Vendor_1bad_Product_f036.kl
new file mode 100644
index 0000000..8cd906a
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_f036.kl
@@ -0,0 +1,36 @@
+# 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.
+
+# MadCatz Generic XBox Controller
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 316 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_1d79_Product_0009.kl b/data/keyboards/Vendor_1d79_Product_0009.kl
new file mode 100644
index 0000000..78fe2cd
--- /dev/null
+++ b/data/keyboards/Vendor_1d79_Product_0009.kl
@@ -0,0 +1,36 @@
+# 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.
+
+# Nyko Playpad / Playpad Pro
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 158 BUTTON_BACK
+key 172 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x02 Z
+axis 0x05 RZ
+axis 0x09 RTRIGGER
+axis 0x0a LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_2378_Product_100a.kl b/data/keyboards/Vendor_2378_Product_100a.kl
new file mode 100644
index 0000000..d9cd171
--- /dev/null
+++ b/data/keyboards/Vendor_2378_Product_100a.kl
@@ -0,0 +1,35 @@
+# 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.
+
+# OnLive, Inc. OnLive Wireless Controller
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_SELECT
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
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/images/mediadrm_decryption_sequence.png b/docs/html/images/mediadrm_decryption_sequence.png
new file mode 100644
index 0000000..2bd95ea
--- /dev/null
+++ b/docs/html/images/mediadrm_decryption_sequence.png
Binary files differ
diff --git a/docs/html/images/mediadrm_overview.png b/docs/html/images/mediadrm_overview.png
new file mode 100644
index 0000000..dd66bce
--- /dev/null
+++ b/docs/html/images/mediadrm_overview.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/docs/html/tools/extras/oem-usb.jd b/docs/html/tools/extras/oem-usb.jd
index 774fe87..87734a1 100644
--- a/docs/html/tools/extras/oem-usb.jd
+++ b/docs/html/tools/extras/oem-usb.jd
@@ -306,6 +306,10 @@
 <tr><td>MTK</td> <td><a
 href="http://online.mediatek.com/Public%20Documents/MTK_Android_USB_Driver.zip">http://online.mediatek.com/Public%20Documents/MTK_Android_USB_Driver.zip</a></td>
 </tr>
+<tr><td>Oppo</td> <td><a
+href="http://www.oppo.com/index.php?q=software/view&sw_id=631"
+>http://www.oppo.com/index.php?q=software/view&sw_id=631</a></td>
+</tr>
 <tr><td>Pantech</td>	<td><a
 href="http://www.isky.co.kr/cs/software/software.sky?fromUrl=index">http://www.isky.co.kr/cs/software/software.sky?fromUrl=index</a></td>
 </tr><tr><td>Pegatron</td>	<td><a
@@ -327,6 +331,9 @@
 href="http://www.yulong.com/product/product/product/downloadList.html#downListUL">http://www.yulong.com/product/product/product/downloadList.html#downListUL</a></td>
 </tr>
 
+<tr><td>Xiaomi</td>  <td><a
+href="http://www.xiaomi.com/c/driver/index.html">http://www.xiaomi.com/c/driver/index.html</a></td>
+</tr>
 <tr>
 <td>ZTE</td>	<td><a
 href="http://support.zte.com.cn/support/news/NewsDetail.aspx?newsId=1000442">http://support.zte.com.cn/support/news/NewsDetail.aspx?newsId=1000442</a></td></tr>
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index ea29b7d..5d1990a 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -277,21 +277,13 @@
                 throw new RSIllegalArgumentException("Invalid usage combination.");
             }
         }
-        if (t != null) {
-            // don't need to account for USAGE_SHARED Allocations
-            if ((usage & USAGE_SHARED) == 0) {
-                int numBytes = t.getCount() * t.getElement().getBytesSize();
-                rs.addAllocSizeForGC(numBytes);
-                mGCSize = numBytes;
-            }
-        }
+
         mType = t;
         mUsage = usage;
 
         if (t != null) {
             updateCacheInfo(t);
         }
-
     }
 
     private void validateIsInt32() {
@@ -355,12 +347,6 @@
             mType.updateFromNative();
             updateCacheInfo(mType);
         }
-        // don't need to account for USAGE_SHARED Allocations
-        if ((mUsage & USAGE_SHARED) == 0) {
-            int numBytes = mType.getCount() * mType.getElement().getBytesSize();
-            mRS.addAllocSizeForGC(numBytes);
-            mGCSize = numBytes;
-        }
     }
 
     /**
@@ -1264,7 +1250,6 @@
         if (type.getID(rs) == 0) {
             throw new RSInvalidStateException("Bad Type");
         }
-
         int id = rs.nAllocationCreateTyped(type.getID(rs), mips.mID, usage, 0);
         if (id == 0) {
             throw new RSRuntimeException("Allocation creation failed.");
@@ -1414,6 +1399,7 @@
             return alloc;
         }
 
+
         int id = rs.nAllocationCreateFromBitmap(t.getID(rs), mips.mID, b, usage);
         if (id == 0) {
             throw new RSRuntimeException("Load failed.");
diff --git a/graphics/java/android/renderscript/BaseObj.java b/graphics/java/android/renderscript/BaseObj.java
index c2ebc9f..f464f9b 100644
--- a/graphics/java/android/renderscript/BaseObj.java
+++ b/graphics/java/android/renderscript/BaseObj.java
@@ -71,9 +71,6 @@
     private int mID;
     private boolean mDestroyed;
     private String mName;
-
-    int mGCSize;
-
     RenderScript mRS;
 
     /**
@@ -138,9 +135,6 @@
             throw new RSInvalidStateException("Object already destroyed.");
         }
         mDestroyed = true;
-        if (mGCSize != 0) {
-            mRS.removeAllocSizeForGC(mGCSize);
-        }
         mRS.nObjDestroy(mID);
     }
 
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 33639dc..6f614c3 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -18,9 +18,7 @@
 
 import java.io.File;
 import java.lang.reflect.Field;
-import java.util.concurrent.locks.*;
 
-import android.app.ActivityManager;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
@@ -804,8 +802,6 @@
     int     mContext;
     @SuppressWarnings({"FieldCanBeLocal"})
     MessageThread mMessageThread;
-    GCThread mGCThread;
-
 
     Element mElement_U8;
     Element mElement_I8;
@@ -1095,60 +1091,6 @@
         }
     }
 
-    static class GCThread extends Thread {
-        RenderScript mRS;
-        boolean mRun = true;
-
-        long currentSize = 0;
-        long targetSize; // call System.gc after 512MB of allocs
-
-        final Lock lock = new ReentrantLock();
-        final Condition cond = lock.newCondition();
-
-        GCThread(RenderScript rs) {
-            super("RSGCThread");
-            mRS = rs;
-
-        }
-
-        public void run() {
-            ActivityManager am = (ActivityManager)mRS.getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
-            ActivityManager.MemoryInfo meminfo = new ActivityManager.MemoryInfo();
-            am.getMemoryInfo(meminfo);
-            targetSize = (long)(meminfo.totalMem * .5f);
-
-            while(mRun) {
-                System.gc();
-                lock.lock();
-                try {
-                    cond.awaitUninterruptibly();
-                } finally {
-                    lock.unlock();
-                }
-            }
-
-            Log.d(LOG_TAG, "GCThread exiting.");
-        }
-
-        public synchronized void addAllocSize(long bytes) {
-            currentSize += bytes;
-            if (currentSize >= targetSize) {
-                lock.lock();
-                try {
-                    cond.signal();
-                } finally {
-                    lock.unlock();
-                }
-            }
-        }
-
-        public synchronized void removeAllocSize(long bytes) {
-            currentSize -= bytes;
-        }
-
-    }
-
-
     RenderScript(Context ctx) {
         if (ctx != null) {
             mApplicationContext = ctx.getApplicationContext();
@@ -1171,15 +1113,6 @@
         return create(ctx, sdkVersion, ContextType.NORMAL);
     }
 
-    void addAllocSizeForGC(int bytes) {
-        mGCThread.addAllocSize(bytes);
-    }
-
-    void removeAllocSizeForGC(int bytes) {
-        mGCThread.removeAllocSize(bytes);
-    }
-
-
     /**
      * Create a basic RenderScript context.
      *
@@ -1196,9 +1129,7 @@
             throw new RSDriverException("Failed to create RS context.");
         }
         rs.mMessageThread = new MessageThread(rs);
-        rs.mGCThread = new GCThread(rs);
         rs.mMessageThread.start();
-        rs.mGCThread.start();
         return rs;
     }
 
@@ -1253,11 +1184,8 @@
         validate();
         nContextDeinitToClient(mContext);
         mMessageThread.mRun = false;
-        mGCThread.mRun = false;
-        mGCThread.addAllocSize(0);
         try {
             mMessageThread.join();
-            mGCThread.join();
         } catch(InterruptedException e) {
         }
 
diff --git a/graphics/java/android/renderscript/RenderScriptGL.java b/graphics/java/android/renderscript/RenderScriptGL.java
index fad8838..52034b1 100644
--- a/graphics/java/android/renderscript/RenderScriptGL.java
+++ b/graphics/java/android/renderscript/RenderScriptGL.java
@@ -198,9 +198,6 @@
         }
         mMessageThread = new MessageThread(this);
         mMessageThread.start();
-        mGCThread = new GCThread(this);
-        mGCThread.start();
-
     }
 
     /**
diff --git a/graphics/java/android/renderscript/ScriptC.java b/graphics/java/android/renderscript/ScriptC.java
index 2f69775..221f760 100644
--- a/graphics/java/android/renderscript/ScriptC.java
+++ b/graphics/java/android/renderscript/ScriptC.java
@@ -60,8 +60,6 @@
             throw new RSRuntimeException("Loading of ScriptC script failed.");
         }
         setID(id);
-        mGCSize = 2 * 1024 * 1024;
-        rs.addAllocSizeForGC(mGCSize);
     }
 
     /**
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/keystore/tests/src/android/security/AndroidKeyStoreTest.java b/keystore/tests/src/android/security/AndroidKeyStoreTest.java
index 05ffe109..507d41c 100644
--- a/keystore/tests/src/android/security/AndroidKeyStoreTest.java
+++ b/keystore/tests/src/android/security/AndroidKeyStoreTest.java
@@ -504,11 +504,13 @@
 
         assertAliases(new String[] {});
 
-        assertTrue(mAndroidKeyStore.generate(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1));
+        assertTrue(mAndroidKeyStore.generate(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         assertAliases(new String[] { TEST_ALIAS_1 });
 
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         assertAliases(new String[] { TEST_ALIAS_1, TEST_ALIAS_2 });
     }
@@ -530,11 +532,13 @@
 
         assertAliases(new String[] {});
 
-        assertTrue(mAndroidKeyStore.generate(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1));
+        assertTrue(mAndroidKeyStore.generate(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         assertTrue("Should contain generated private key", mKeyStore.containsAlias(TEST_ALIAS_1));
 
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         assertTrue("Should contain added CA certificate", mKeyStore.containsAlias(TEST_ALIAS_2));
 
@@ -547,7 +551,8 @@
 
         mKeyStore.load(null, null);
 
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         assertTrue("Should contain added CA certificate", mKeyStore.containsAlias(TEST_ALIAS_2));
     }
@@ -567,15 +572,19 @@
 
         // TEST_ALIAS_1
         assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                FAKE_KEY_1));
-        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+                FAKE_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
+        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         // TEST_ALIAS_2
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         // TEST_ALIAS_3
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_3, FAKE_CA_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_3, FAKE_CA_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         assertAliases(new String[] { TEST_ALIAS_1, TEST_ALIAS_2, TEST_ALIAS_3 });
 
@@ -608,9 +617,11 @@
 
         // TEST_ALIAS_1
         assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                FAKE_KEY_1));
-        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+                FAKE_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
+        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         // Should not throw when a non-existent entry is requested for delete.
         mKeyStore.deleteEntry(TEST_ALIAS_2);
@@ -621,7 +632,8 @@
 
         mKeyStore.load(null, null);
 
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         assertAliases(new String[] { TEST_ALIAS_1 });
 
@@ -652,7 +664,8 @@
 
         mKeyStore.load(null, null);
 
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         CertificateFactory f = CertificateFactory.getInstance("X.509");
         Certificate actual = f.generateCertificate(new ByteArrayInputStream(FAKE_CA_1));
@@ -668,9 +681,11 @@
         mKeyStore.load(null, null);
 
         assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                FAKE_KEY_1));
-        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+                FAKE_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
+        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         CertificateFactory f = CertificateFactory.getInstance("X.509");
         Certificate actual = f.generateCertificate(new ByteArrayInputStream(FAKE_USER_1));
@@ -686,13 +701,16 @@
         mKeyStore.load(null, null);
 
         // Insert TrustedCertificateEntry with CA name
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         // Insert PrivateKeyEntry that uses the same CA
         assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                FAKE_KEY_1));
-        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+                FAKE_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
+        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         CertificateFactory f = CertificateFactory.getInstance("X.509");
         Certificate actual = f.generateCertificate(new ByteArrayInputStream(FAKE_CA_1));
@@ -719,7 +737,8 @@
 
         mKeyStore.load(null, null);
 
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         CertificateFactory f = CertificateFactory.getInstance("X.509");
         Certificate userCert = f.generateCertificate(new ByteArrayInputStream(FAKE_USER_1));
@@ -734,9 +753,11 @@
         mKeyStore.load(null, null);
 
         assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                FAKE_KEY_1));
-        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+                FAKE_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
+        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         CertificateFactory cf = CertificateFactory.getInstance("X.509");
         Certificate[] expected = new Certificate[2];
@@ -771,9 +792,11 @@
         mKeyStore.load(null, null);
 
         assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                FAKE_KEY_1));
-        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+                FAKE_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
+        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         Date now = new Date();
         Date actual = mKeyStore.getCreationDate(TEST_ALIAS_1);
@@ -810,7 +833,8 @@
 
         mKeyStore.load(null, null);
 
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         Date now = new Date();
         Date actual = mKeyStore.getCreationDate(TEST_ALIAS_1);
@@ -829,9 +853,11 @@
         mKeyStore.load(null, null);
 
         assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                FAKE_KEY_1));
-        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+                FAKE_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
+        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         Entry entry = mKeyStore.getEntry(TEST_ALIAS_1, null);
         assertNotNull("Entry should exist", entry);
@@ -930,9 +956,11 @@
         mKeyStore.load(null, null);
 
         assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                FAKE_KEY_1));
-        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+                FAKE_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
+        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         Key key = mKeyStore.getKey(TEST_ALIAS_1, null);
         assertNotNull("Key should exist", key);
@@ -977,7 +1005,8 @@
 
         mKeyStore.load(null, null);
 
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         assertNull("Certificate entries should return null", mKeyStore.getKey(TEST_ALIAS_1, null));
     }
@@ -1006,7 +1035,8 @@
         setupPassword();
         mKeyStore.load(null, null);
 
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         assertTrue("Should return true for CA certificate",
                 mKeyStore.isCertificateEntry(TEST_ALIAS_1));
@@ -1017,9 +1047,11 @@
         mKeyStore.load(null, null);
 
         assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                FAKE_KEY_1));
-        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+                FAKE_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
+        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         assertFalse("Should return false for PrivateKeyEntry",
                 mKeyStore.isCertificateEntry(TEST_ALIAS_1));
@@ -1045,9 +1077,11 @@
         mKeyStore.load(null, null);
 
         assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                FAKE_KEY_1));
-        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+                FAKE_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
+        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         assertTrue("Should return true for PrivateKeyEntry", mKeyStore.isKeyEntry(TEST_ALIAS_1));
     }
@@ -1056,7 +1090,8 @@
         setupPassword();
         mKeyStore.load(null, null);
 
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         assertFalse("Should return false for CA certificate", mKeyStore.isKeyEntry(TEST_ALIAS_1));
     }
@@ -1089,7 +1124,8 @@
         setupPassword();
         mKeyStore.load(null, null);
 
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         assertAliases(new String[] { TEST_ALIAS_1 });
 
@@ -1107,9 +1143,11 @@
         mKeyStore.load(null, null);
 
         assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                FAKE_KEY_1));
-        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+                FAKE_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
+        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         assertAliases(new String[] { TEST_ALIAS_1 });
 
@@ -1596,7 +1634,8 @@
         // Create key #1
         {
             final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1;
-            assertTrue(mAndroidKeyStore.generate(privateKeyAlias));
+            assertTrue(mAndroidKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF,
+                    KeyStore.FLAG_ENCRYPTED));
 
             Key key = mKeyStore.getKey(TEST_ALIAS_1, null);
 
@@ -1608,7 +1647,7 @@
                     TEST_SERIAL_1, TEST_DN_1, NOW, NOW_PLUS_10_YEARS);
 
             assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1,
-                    expectedCert.getEncoded()));
+                    expectedCert.getEncoded(), KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
             Entry entry = mKeyStore.getEntry(TEST_ALIAS_1, null);
 
@@ -1651,25 +1690,27 @@
         // Create key #1
         {
             final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1;
-            assertTrue(mAndroidKeyStore.generate(privateKeyAlias));
+            assertTrue(mAndroidKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF,
+                    KeyStore.FLAG_ENCRYPTED));
 
             X509Certificate cert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_1,
                     TEST_SERIAL_1, TEST_DN_1, NOW, NOW_PLUS_10_YEARS);
 
             assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1,
-                    cert.getEncoded()));
+                    cert.getEncoded(), KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
         }
 
         // Create key #2
         {
             final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_2;
-            assertTrue(mAndroidKeyStore.generate(privateKeyAlias));
+            assertTrue(mAndroidKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF,
+                    KeyStore.FLAG_ENCRYPTED));
 
             X509Certificate cert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_2,
                     TEST_SERIAL_2, TEST_DN_2, NOW, NOW_PLUS_10_YEARS);
 
             assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_2,
-                    cert.getEncoded()));
+                    cert.getEncoded(), KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
         }
 
         // Replace key #1 with key #2
@@ -1731,17 +1772,20 @@
         setupPassword();
         mKeyStore.load(null, null);
 
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         assertEquals("The keystore size should match expected", 1, mKeyStore.size());
         assertAliases(new String[] { TEST_ALIAS_1 });
 
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         assertEquals("The keystore size should match expected", 2, mKeyStore.size());
         assertAliases(new String[] { TEST_ALIAS_1, TEST_ALIAS_2 });
 
-        assertTrue(mAndroidKeyStore.generate(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_3));
+        assertTrue(mAndroidKeyStore.generate(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_3,
+                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         assertEquals("The keystore size should match expected", 3, mKeyStore.size());
         assertAliases(new String[] { TEST_ALIAS_1, TEST_ALIAS_2, TEST_ALIAS_3 });
@@ -1807,13 +1851,14 @@
 
     private void setupKey() throws Exception {
         final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1;
-        assertTrue(mAndroidKeyStore.generate(privateKeyAlias));
+        assertTrue(mAndroidKeyStore
+                .generate(privateKeyAlias, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         X509Certificate cert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_1, TEST_SERIAL_1,
                 TEST_DN_1, NOW, NOW_PLUS_10_YEARS);
 
         assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1,
-                cert.getEncoded()));
+                cert.getEncoded(), KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     }
 
     public void testKeyStore_KeyOperations_Wrap_Encrypted_Success() throws Exception {
diff --git a/keystore/tests/src/android/security/KeyStoreTest.java b/keystore/tests/src/android/security/KeyStoreTest.java
index 1de1eaf..815f4ac 100644
--- a/keystore/tests/src/android/security/KeyStoreTest.java
+++ b/keystore/tests/src/android/security/KeyStoreTest.java
@@ -142,42 +142,51 @@
         assertNull(mKeyStore.get(TEST_KEYNAME));
         mKeyStore.password(TEST_PASSWD);
         assertNull(mKeyStore.get(TEST_KEYNAME));
-        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE));
+        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, KeyStore.UID_SELF,
+                KeyStore.FLAG_ENCRYPTED));
         assertTrue(Arrays.equals(TEST_KEYVALUE, mKeyStore.get(TEST_KEYNAME)));
     }
 
     public void testPut() throws Exception {
         assertNull(mKeyStore.get(TEST_KEYNAME));
-        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE));
+        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, KeyStore.UID_SELF,
+                KeyStore.FLAG_ENCRYPTED));
         assertFalse(mKeyStore.contains(TEST_KEYNAME));
         mKeyStore.password(TEST_PASSWD);
-        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE));
+        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, KeyStore.UID_SELF,
+                KeyStore.FLAG_ENCRYPTED));
         assertTrue(Arrays.equals(TEST_KEYVALUE, mKeyStore.get(TEST_KEYNAME)));
     }
 
     public void testPut_grantedUid_Wifi() throws Exception {
         assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
-        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID));
+        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID,
+                KeyStore.FLAG_ENCRYPTED));
         assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
         mKeyStore.password(TEST_PASSWD);
-        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID));
+        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID,
+                KeyStore.FLAG_ENCRYPTED));
         assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
     }
 
     public void testPut_ungrantedUid_Bluetooth() throws Exception {
         assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
-        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID));
+        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID,
+                KeyStore.FLAG_ENCRYPTED));
         assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
         mKeyStore.password(TEST_PASSWD);
-        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID));
+        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID,
+                KeyStore.FLAG_ENCRYPTED));
         assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
     }
 
     public void testI18n() throws Exception {
-        assertFalse(mKeyStore.put(TEST_I18N_KEY, TEST_I18N_VALUE));
+        assertFalse(mKeyStore.put(TEST_I18N_KEY, TEST_I18N_VALUE, KeyStore.UID_SELF,
+                KeyStore.FLAG_ENCRYPTED));
         assertFalse(mKeyStore.contains(TEST_I18N_KEY));
         mKeyStore.password(TEST_I18N_KEY);
-        assertTrue(mKeyStore.put(TEST_I18N_KEY, TEST_I18N_VALUE));
+        assertTrue(mKeyStore.put(TEST_I18N_KEY, TEST_I18N_VALUE, KeyStore.UID_SELF,
+                KeyStore.FLAG_ENCRYPTED));
         assertTrue(mKeyStore.contains(TEST_I18N_KEY));
     }
 
@@ -186,7 +195,8 @@
         mKeyStore.password(TEST_PASSWD);
         assertFalse(mKeyStore.delete(TEST_KEYNAME));
 
-        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE));
+        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, KeyStore.UID_SELF,
+                KeyStore.FLAG_ENCRYPTED));
         assertTrue(Arrays.equals(TEST_KEYVALUE, mKeyStore.get(TEST_KEYNAME)));
         assertTrue(mKeyStore.delete(TEST_KEYNAME));
         assertNull(mKeyStore.get(TEST_KEYNAME));
@@ -197,7 +207,8 @@
         mKeyStore.password(TEST_PASSWD);
         assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.WIFI_UID));
 
-        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID));
+        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID,
+                KeyStore.FLAG_ENCRYPTED));
         assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
         assertTrue(mKeyStore.delete(TEST_KEYNAME, Process.WIFI_UID));
         assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
@@ -208,7 +219,8 @@
         mKeyStore.password(TEST_PASSWD);
         assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.BLUETOOTH_UID));
 
-        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID));
+        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID,
+                KeyStore.FLAG_ENCRYPTED));
         assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
         assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.BLUETOOTH_UID));
         assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
@@ -220,7 +232,8 @@
         assertTrue(mKeyStore.password(TEST_PASSWD));
         assertFalse(mKeyStore.contains(TEST_KEYNAME));
 
-        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE));
+        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, KeyStore.UID_SELF,
+                KeyStore.FLAG_ENCRYPTED));
         assertTrue(mKeyStore.contains(TEST_KEYNAME));
     }
 
@@ -230,7 +243,8 @@
         assertTrue(mKeyStore.password(TEST_PASSWD));
         assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
 
-        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID));
+        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID,
+                KeyStore.FLAG_ENCRYPTED));
         assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
     }
 
@@ -240,7 +254,8 @@
         assertTrue(mKeyStore.password(TEST_PASSWD));
         assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
 
-        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID));
+        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID,
+                KeyStore.FLAG_ENCRYPTED));
         assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
     }
 
@@ -250,8 +265,8 @@
         assertEquals(0, emptyResult.length);
 
         mKeyStore.password(TEST_PASSWD);
-        mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE);
-        mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE);
+        mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED);
+        mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED);
 
         String[] results = mKeyStore.saw(TEST_KEYNAME);
         assertEquals(new HashSet(Arrays.asList(TEST_KEYNAME1.substring(TEST_KEYNAME.length()),
@@ -264,8 +279,8 @@
         assertNull(results1);
 
         mKeyStore.password(TEST_PASSWD);
-        mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE);
-        mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE);
+        mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED);
+        mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED);
 
         String[] results2 = mKeyStore.saw(TEST_KEYNAME, Process.BLUETOOTH_UID);
         assertNull(results2);
@@ -277,8 +292,8 @@
         assertEquals(0, results1.length);
 
         mKeyStore.password(TEST_PASSWD);
-        mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, Process.WIFI_UID);
-        mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, Process.WIFI_UID);
+        mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, Process.WIFI_UID, KeyStore.FLAG_ENCRYPTED);
+        mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, Process.WIFI_UID, KeyStore.FLAG_ENCRYPTED);
 
         String[] results2 = mKeyStore.saw(TEST_KEYNAME, Process.WIFI_UID);
         assertEquals(new HashSet(Arrays.asList(TEST_KEYNAME1.substring(TEST_KEYNAME.length()),
@@ -292,8 +307,8 @@
         assertEquals(0, results1.length);
 
         mKeyStore.password(TEST_PASSWD);
-        mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, Process.VPN_UID);
-        mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, Process.VPN_UID);
+        mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, Process.VPN_UID, KeyStore.FLAG_ENCRYPTED);
+        mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, Process.VPN_UID, KeyStore.FLAG_ENCRYPTED);
 
         String[] results2 = mKeyStore.saw(TEST_KEYNAME, Process.VPN_UID);
         assertEquals(new HashSet(Arrays.asList(TEST_KEYNAME1.substring(TEST_KEYNAME.length()),
@@ -324,7 +339,7 @@
         assertTrue(mKeyStore.isEmpty());
         mKeyStore.password(TEST_PASSWD);
         assertTrue(mKeyStore.isEmpty());
-        mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE);
+        mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED);
         assertFalse(mKeyStore.isEmpty());
         mKeyStore.reset();
         assertTrue(mKeyStore.isEmpty());
@@ -332,20 +347,21 @@
 
     public void testGenerate_NotInitialized_Fail() throws Exception {
         assertFalse("Should fail when keystore is not initialized",
-                mKeyStore.generate(TEST_KEYNAME));
+                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     }
 
     public void testGenerate_Locked_Fail() throws Exception {
         mKeyStore.password(TEST_PASSWD);
         mKeyStore.lock();
-        assertFalse("Should fail when keystore is locked", mKeyStore.generate(TEST_KEYNAME));
+        assertFalse("Should fail when keystore is locked",
+                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     }
 
     public void testGenerate_Success() throws Exception {
         assertTrue(mKeyStore.password(TEST_PASSWD));
 
         assertTrue("Should be able to generate key when unlocked",
-                mKeyStore.generate(TEST_KEYNAME));
+                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
         assertTrue(mKeyStore.contains(TEST_KEYNAME));
         assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
     }
@@ -354,7 +370,7 @@
         assertTrue(mKeyStore.password(TEST_PASSWD));
 
         assertTrue("Should be able to generate key when unlocked",
-                mKeyStore.generate(TEST_KEYNAME, Process.WIFI_UID));
+                mKeyStore.generate(TEST_KEYNAME, Process.WIFI_UID, KeyStore.FLAG_ENCRYPTED));
         assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
         assertFalse(mKeyStore.contains(TEST_KEYNAME));
     }
@@ -362,7 +378,7 @@
     public void testGenerate_ungrantedUid_Bluetooth_Failure() throws Exception {
         assertTrue(mKeyStore.password(TEST_PASSWD));
 
-        assertFalse(mKeyStore.generate(TEST_KEYNAME, Process.BLUETOOTH_UID));
+        assertFalse(mKeyStore.generate(TEST_KEYNAME, Process.BLUETOOTH_UID, KeyStore.FLAG_ENCRYPTED));
         assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
         assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
         assertFalse(mKeyStore.contains(TEST_KEYNAME));
@@ -371,8 +387,8 @@
     public void testImport_Success() throws Exception {
         assertTrue(mKeyStore.password(TEST_PASSWD));
 
-        assertTrue("Should be able to import key when unlocked",
-                mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES));
+        assertTrue("Should be able to import key when unlocked", mKeyStore.importKey(TEST_KEYNAME,
+                PRIVKEY_BYTES, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
         assertTrue(mKeyStore.contains(TEST_KEYNAME));
         assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
     }
@@ -380,8 +396,8 @@
     public void testImport_grantedUid_Wifi_Success() throws Exception {
         assertTrue(mKeyStore.password(TEST_PASSWD));
 
-        assertTrue("Should be able to import key when unlocked",
-                mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES, Process.WIFI_UID));
+        assertTrue("Should be able to import key when unlocked", mKeyStore.importKey(TEST_KEYNAME,
+                PRIVKEY_BYTES, Process.WIFI_UID, KeyStore.FLAG_ENCRYPTED));
         assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
         assertFalse(mKeyStore.contains(TEST_KEYNAME));
     }
@@ -389,7 +405,8 @@
     public void testImport_ungrantedUid_Bluetooth_Failure() throws Exception {
         assertTrue(mKeyStore.password(TEST_PASSWD));
 
-        assertFalse(mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES, Process.BLUETOOTH_UID));
+        assertFalse(mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES, Process.BLUETOOTH_UID,
+                KeyStore.FLAG_ENCRYPTED));
         assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
         assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
         assertFalse(mKeyStore.contains(TEST_KEYNAME));
@@ -398,8 +415,8 @@
     public void testImport_Failure_BadEncoding() throws Exception {
         mKeyStore.password(TEST_PASSWD);
 
-        assertFalse("Invalid DER-encoded key should not be imported",
-                mKeyStore.importKey(TEST_KEYNAME, TEST_DATA));
+        assertFalse("Invalid DER-encoded key should not be imported", mKeyStore.importKey(
+                TEST_KEYNAME, TEST_DATA, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
         assertFalse(mKeyStore.contains(TEST_KEYNAME));
         assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
     }
@@ -407,7 +424,7 @@
     public void testSign_Success() throws Exception {
         mKeyStore.password(TEST_PASSWD);
 
-        assertTrue(mKeyStore.generate(TEST_KEYNAME));
+        assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
         assertTrue(mKeyStore.contains(TEST_KEYNAME));
         final byte[] signature = mKeyStore.sign(TEST_KEYNAME, TEST_DATA);
 
@@ -417,7 +434,7 @@
     public void testVerify_Success() throws Exception {
         mKeyStore.password(TEST_PASSWD);
 
-        assertTrue(mKeyStore.generate(TEST_KEYNAME));
+        assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
         assertTrue(mKeyStore.contains(TEST_KEYNAME));
         final byte[] signature = mKeyStore.sign(TEST_KEYNAME, TEST_DATA);
 
@@ -444,7 +461,7 @@
                 mKeyStore.password(TEST_PASSWD));
 
         assertTrue("Should be able to generate key for testcase",
-                mKeyStore.generate(TEST_KEYNAME));
+                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         assertTrue("Should be able to grant key to other user",
                 mKeyStore.grant(TEST_KEYNAME, 0));
@@ -453,8 +470,8 @@
     public void testGrant_Imported_Success() throws Exception {
         assertTrue("Password should work for keystore", mKeyStore.password(TEST_PASSWD));
 
-        assertTrue("Should be able to import key for testcase",
-                mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES));
+        assertTrue("Should be able to import key for testcase", mKeyStore.importKey(TEST_KEYNAME,
+                PRIVKEY_BYTES, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         assertTrue("Should be able to grant key to other user", mKeyStore.grant(TEST_KEYNAME, 0));
     }
@@ -477,7 +494,7 @@
                 mKeyStore.password(TEST_PASSWD));
 
         assertTrue("Should be able to generate key for testcase",
-                mKeyStore.generate(TEST_KEYNAME));
+                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         assertTrue("Should be able to grant key to other user",
                 mKeyStore.grant(TEST_KEYNAME, 0));
@@ -490,8 +507,8 @@
         assertTrue("Password should work for keystore",
                 mKeyStore.password(TEST_PASSWD));
 
-        assertTrue("Should be able to import key for testcase",
-                mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES));
+        assertTrue("Should be able to import key for testcase", mKeyStore.importKey(TEST_KEYNAME,
+                PRIVKEY_BYTES, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         assertTrue("Should be able to grant key to other user",
                 mKeyStore.grant(TEST_KEYNAME, 0));
@@ -510,7 +527,7 @@
                 mKeyStore.password(TEST_PASSWD));
 
         assertTrue("Should be able to generate key for testcase",
-                mKeyStore.generate(TEST_KEYNAME));
+                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         assertFalse("Should not be able to revoke not existent grant",
                 mKeyStore.ungrant(TEST_KEYNAME, 0));
@@ -521,7 +538,7 @@
                 mKeyStore.password(TEST_PASSWD));
 
         assertTrue("Should be able to generate key for testcase",
-                mKeyStore.generate(TEST_KEYNAME));
+                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         assertTrue("Should be able to grant key to other user",
                 mKeyStore.grant(TEST_KEYNAME, 0));
@@ -538,7 +555,7 @@
                 mKeyStore.password(TEST_PASSWD));
 
         assertTrue("Should be able to generate key for testcase",
-                mKeyStore.generate(TEST_KEYNAME));
+                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         assertTrue("Should be able to grant key to other user",
                 mKeyStore.grant(TEST_KEYNAME, 0));
@@ -558,7 +575,7 @@
 
         assertFalse(mKeyStore.contains(TEST_KEYNAME));
 
-        assertTrue(mKeyStore.generate(TEST_KEYNAME));
+        assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         assertTrue(mKeyStore.contains(TEST_KEYNAME));
         assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
@@ -596,7 +613,7 @@
 
         assertFalse(mKeyStore.contains(TEST_KEYNAME));
 
-        assertTrue(mKeyStore.generate(TEST_KEYNAME));
+        assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         assertTrue(mKeyStore.contains(TEST_KEYNAME));
         assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
@@ -619,8 +636,8 @@
         assertTrue("Password should work for keystore",
                 mKeyStore.password(TEST_PASSWD));
 
-        assertTrue("Should be able to import key when unlocked",
-                mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES));
+        assertTrue("Should be able to import key when unlocked", mKeyStore.importKey(TEST_KEYNAME,
+                PRIVKEY_BYTES, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         long now = System.currentTimeMillis();
         long actual = mKeyStore.getmtime(TEST_KEYNAME);
@@ -650,8 +667,8 @@
         assertTrue("Password should work for keystore",
                 mKeyStore.password(TEST_PASSWD));
 
-        assertTrue("Should be able to import key when unlocked",
-                mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES));
+        assertTrue("Should be able to import key when unlocked", mKeyStore.importKey(TEST_KEYNAME,
+                PRIVKEY_BYTES, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
 
         assertEquals("-1 should be returned for non-existent key",
                 -1L, mKeyStore.getmtime(TEST_KEYNAME2));
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/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..c277c24 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,16 @@
         return true;
     }
 
+    bool mergeAllowed() {
+        if (!state.mMatrix.isPureTranslate()) return false;
+
+        // 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 +725,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 +790,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 +798,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 +817,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 +829,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 +845,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 +855,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 +870,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 +880,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 +905,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 +918,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 +942,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 +970,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 +987,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 +1005,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 +1015,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 +1031,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 +1053,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 +1074,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 +1093,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 +1124,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 +1142,6 @@
 
     virtual const char* name() { return "DrawPath"; }
 
-    virtual DeferredDisplayList::OpBatchId getBatchId() {
-        return DeferredDisplayList::kOpBatch_AlphaMaskTexture;
-    }
 private:
     SkPath* mPath;
 };
@@ -1063,7 +1154,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 +1164,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 +1181,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 +1201,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 +1228,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 +1249,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 +1282,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 +1290,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 +1348,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 +1376,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 +1406,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 6894ef9..543cfa2 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -57,7 +57,6 @@
 
     mGammaTable = NULL;
     mInitialized = false;
-    mMaxNumberOfQuads = 1024;
 
     mCurrentCacheTexture = NULL;
 
@@ -293,7 +292,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);
@@ -320,12 +319,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;
 
@@ -594,7 +593,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;
@@ -602,7 +601,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 348b7e3..307a1d9 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -66,7 +66,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);
@@ -101,6 +102,8 @@
 private:
     friend class Font;
 
+    static const uint32_t gMaxNumberOfQuads = 2048;
+
     const uint8_t* mGammaTable;
 
     void allocateTextureMemory(CacheTexture* cacheTexture);
@@ -154,7 +157,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/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 917a47d..56e98e4 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -24,6 +24,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -1205,6 +1206,11 @@
      * call {@link #stopBluetoothSco()} to clear the request and turn down the bluetooth connection.
      * <p>Even if a SCO connection is established, the following restrictions apply on audio
      * output streams so that they can be routed to SCO headset:
+     * <p>NOTE: up to and including API version
+     * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method initiates a virtual
+     * voice call to the bluetooth headset.
+     * After API version {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2} only a raw SCO audio
+     * connection is established.
      * <ul>
      *   <li> the stream type must be {@link #STREAM_VOICE_CALL} </li>
      *   <li> the format must be mono </li>
@@ -1226,7 +1232,7 @@
     public void startBluetoothSco(){
         IAudioService service = getService();
         try {
-            service.startBluetoothSco(mICallBack);
+            service.startBluetoothSco(mICallBack, mContext.getApplicationInfo().targetSdkVersion);
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in startBluetoothSco", e);
         }
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 637ac85..0df4f82 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -48,6 +48,7 @@
 import android.media.MediaPlayer.OnCompletionListener;
 import android.media.MediaPlayer.OnErrorListener;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
@@ -369,6 +370,14 @@
     // waiting for headset service to connect
     private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
 
+    // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
+    // originated from an app targeting an API version before JB MR2 and raw audio after that.
+    private int mScoAudioMode;
+    // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
+    private static final int SCO_MODE_VIRTUAL_CALL = 0;
+    // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
+    private static final int SCO_MODE_RAW = 1;
+
     // Current connection state indicated by bluetooth headset
     private int mScoConnectionState;
 
@@ -1910,7 +1919,7 @@
     }
 
     /** @see AudioManager#startBluetoothSco() */
-    public void startBluetoothSco(IBinder cb){
+    public void startBluetoothSco(IBinder cb, int targetSdkVersion){
         if (!checkAudioSettingsPermission("startBluetoothSco()") ||
                 !mBootCompleted) {
             return;
@@ -1922,7 +1931,7 @@
         // The caller identity must be cleared after getScoClient() because it is needed if a new
         // client is created.
         final long ident = Binder.clearCallingIdentity();
-        client.incCount();
+        client.incCount(targetSdkVersion);
         Binder.restoreCallingIdentity(ident);
     }
 
@@ -1968,9 +1977,9 @@
             }
         }
 
-        public void incCount() {
+        public void incCount(int targetSdkVersion) {
             synchronized(mScoClients) {
-                requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED);
+                requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, targetSdkVersion);
                 if (mStartcount == 0) {
                     try {
                         mCb.linkToDeath(this, 0);
@@ -1996,7 +2005,7 @@
                             Log.w(TAG, "decCount() going to 0 but not registered to binder");
                         }
                     }
-                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
+                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
                 }
             }
         }
@@ -2012,7 +2021,7 @@
                 }
                 mStartcount = 0;
                 if (stopSco) {
-                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
+                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
                 }
             }
         }
@@ -2040,7 +2049,7 @@
             }
         }
 
-        private void requestScoState(int state) {
+        private void requestScoState(int state, int targetSdkVersion) {
             checkScoAudioState();
             if (totalCount() == 0) {
                 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
@@ -2055,8 +2064,18 @@
                                 (mScoAudioState == SCO_STATE_INACTIVE ||
                                  mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
                             if (mScoAudioState == SCO_STATE_INACTIVE) {
+                                mScoAudioMode =
+                                        (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
+                                                SCO_MODE_VIRTUAL_CALL : SCO_MODE_RAW;
                                 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
-                                    if (mBluetoothHeadset.connectAudio()) {
+                                    boolean status;
+                                    if (mScoAudioMode == SCO_MODE_RAW) {
+                                        status = mBluetoothHeadset.connectAudio();
+                                    } else {
+                                        status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
+                                                                            mBluetoothHeadsetDevice);
+                                    }
+                                    if (status) {
                                         mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
                                     } else {
                                         broadcastScoConnectionState(
@@ -2078,7 +2097,14 @@
                                mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
                     if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
                         if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
-                            if (!mBluetoothHeadset.disconnectAudio()) {
+                            boolean status;
+                            if (mScoAudioMode == SCO_MODE_RAW) {
+                                status = mBluetoothHeadset.disconnectAudio();
+                            } else {
+                                status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
+                                                                        mBluetoothHeadsetDevice);
+                            }
+                            if (!status) {
                                 mScoAudioState = SCO_STATE_INACTIVE;
                                 broadcastScoConnectionState(
                                         AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
@@ -2251,10 +2277,20 @@
                             switch (mScoAudioState) {
                             case SCO_STATE_ACTIVATE_REQ:
                                 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
-                                status = mBluetoothHeadset.connectAudio();
+                                if (mScoAudioMode == SCO_MODE_RAW) {
+                                    status = mBluetoothHeadset.connectAudio();
+                                } else {
+                                    status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
+                                                                        mBluetoothHeadsetDevice);
+                                }
                                 break;
                             case SCO_STATE_DEACTIVATE_REQ:
-                                status = mBluetoothHeadset.disconnectAudio();
+                                if (mScoAudioMode == SCO_MODE_RAW) {
+                                    status = mBluetoothHeadset.disconnectAudio();
+                                } else {
+                                    status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
+                                                                        mBluetoothHeadsetDevice);
+                                }
                                 break;
                             case SCO_STATE_DEACTIVATE_EXT_REQ:
                                 status = mBluetoothHeadset.stopVoiceRecognition(
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 13f6c02..0d285fc 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -179,7 +179,7 @@
            int  getRemoteStreamVolume();
     oneway void registerRemoteVolumeObserverForRcc(int rccId, in IRemoteVolumeObserver rvo);
 
-    void startBluetoothSco(IBinder cb);
+    void startBluetoothSco(IBinder cb, int targetSdkVersion);
     void stopBluetoothSco(IBinder cb);
 
     void forceVolumeControlStream(int streamType, IBinder cb);
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 1501c79..df87db3 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -44,7 +44,16 @@
         return MediaCodecList.getSupportedTypes(mIndex);
     }
 
+    /**
+     * Encapsulates the capabilities of a given codec component,
+     * i.e. what profile/level combinations it supports and what colorspaces
+     * it is capable of providing the decoded data in.
+     */
     public static final class CodecCapabilities {
+        // Enumerates supported profile/level combinations as defined
+        // by the type of encoded data. These combinations impose restrictions
+        // on video resolution, bitrate... and limit the available encoder tools
+        // such as B-frame support, arithmetic coding...
         public CodecProfileLevel[] profileLevels;
 
         // from OMX_COLOR_FORMATTYPE
@@ -219,6 +228,11 @@
         public int level;
     };
 
+    /**
+     * Enumerates the capabilities of the codec component. Since a single
+     * component can support data of a variety of types, the type has to be
+     * specified to yield a meaningful result.
+     */
     public final CodecCapabilities getCapabilitiesForType(
             String type) {
         return MediaCodecList.getCodecCapabilities(mIndex, type);
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 4eb0c56..31fbc4a 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -29,25 +29,69 @@
 import android.util.Log;
 
 /**
- * MediaDrm can be used in conjunction with {@link android.media.MediaCrypto}
- * to obtain keys for decrypting protected media data.
- *
- * Crypto schemes are assigned 16 byte UUIDs,
- * the method {@link #isCryptoSchemeSupported} can be used to query if a given
- * scheme is supported on the device.
- *
+ * MediaDrm can be used to obtain keys for decrypting protected media streams, in
+ * conjunction with {@link android.media.MediaCrypto}.  The MediaDrm APIs
+ * are designed to support the ISO/IEC 23001-7: Common Encryption standard, but
+ * may also be used to implement other encryption schemes.
+ * <p>
+ * Encrypted content is prepared using an encryption server and stored in a content
+ * library. The encrypted content is streamed or downloaded from the content library to
+ * client devices via content servers.  Licenses to view the content are obtained from
+ * a License Server.
+ * <p>
+ * <p><img src="../../../images/mediadrm_overview.png"
+ *      alt="MediaDrm Overview diagram"
+ *      border="0" /></p>
+ * <p>
+ * Keys are requested from the license server using a key request. The key
+ * response is delivered to the client app, which provides the response to the
+ * MediaDrm API.
+ * <p>
+ * A Provisioning server may be required to distribute device-unique credentials to
+ * the devices.
+ * <p>
+ * Enforcing requirements related to the number of devices that may play content
+ * simultaneously can be performed either through key renewal or using the secure
+ * stop methods.
+ * <p>
+ * The following sequence diagram shows the interactions between the objects
+ * involved while playing back encrypted content:
+ * <p>
+ * <p><img src="../../../images/mediadrm_decryption_sequence.png"
+ *         alt="MediaDrm Overview diagram"
+ *         border="0" /></p>
+ * <p>
+ * The app first constructs {@link android.media.MediaExtractor} and
+ * {@link android.media.MediaCodec} objects. It accesses the DRM-scheme-identifying UUID,
+ * typically from metadata in the content, and uses this UUID to construct an instance
+ * of a MediaDrm object that is able to support the DRM scheme required by the content.
+ * Crypto schemes are assigned 16 byte UUIDs.  The method {@link #isCryptoSchemeSupported}
+ * can be used to query if a given scheme is supported on the device.
+ * <p>
+ * The app calls {@link #openSession} to generate a sessionId that will uniquely identify
+ * the session in subsequent interactions. The app next uses the MediaDrm object to
+ * obtain a key request message and send it to the license server, then provide
+ * the server's response to the MediaDrm object.
+ * <p>
+ * Once the app has a sessionId, it can construct a MediaCrypto object from the UUID and
+ * sessionId.  The MediaCrypto object is registered with the MediaCodec in the
+ * {@link MediaCodec.#configure} method to enable the codec to decrypt content.
+ * <p>
+ * When the app has constructed {@link android.media.MediaExtractor},
+ * {@link android.media.MediaCodec} and {@link android.media.MediaCrypto} objects,
+ * it proceeds to pull samples from the extractor and queue them into the decoder.  For
+ * encrypted content, the samples returned from the extractor remain encrypted, they
+ * are only decrypted when the samples are delivered to the decoder.
+ * <p>
  * <a name="Callbacks"></a>
  * <h3>Callbacks</h3>
- * <p>Applications may want to register for informational events in order
- * to be informed of some internal state update during playback or streaming.
+ * <p>Applications should register for informational events in order
+ * to be informed of key state updates during playback or streaming.
  * Registration for these events is done via a call to
- * {@link #setOnEventListener(OnInfoListener)}setOnInfoListener,
- * In order to receive the respective callback
- * associated with this listener, applications are required to create
+ * {@link #setOnEventListener}. In order to receive the respective
+ * callback associated with this listener, applications are required to create
  * MediaDrm objects on a thread with its own Looper running (main UI
  * thread by default has a Looper running).
- *
- * @hide -- don't expose yet
  */
 public final class MediaDrm {
 
@@ -116,7 +160,7 @@
 
     /**
      * Interface definition for a callback to be invoked when a drm event
-     * occurs.
+     * occurs
      */
     public interface OnEventListener
     {
@@ -132,10 +176,30 @@
         void onEvent(MediaDrm md, byte[] sessionId, int event, int extra, byte[] data);
     }
 
-    public static final int MEDIA_DRM_EVENT_PROVISION_REQUIRED = 1;
-    public static final int MEDIA_DRM_EVENT_KEY_REQUIRED = 2;
-    public static final int MEDIA_DRM_EVENT_KEY_EXPIRED = 3;
-    public static final int MEDIA_DRM_EVENT_VENDOR_DEFINED = 4;
+    /**
+     * This event type indicates that the app needs to request a certificate from
+     * the provisioning server.  The request message data is obtained using
+     * {@link #getProvisionRequest}
+     */
+    public static final int EVENT_PROVISION_REQUIRED = 1;
+
+    /**
+     * This event type indicates that the app needs to request keys from a license
+     * server.  The request message data is obtained using {@link #getKeyRequest}.
+     */
+    public static final int EVENT_KEY_REQUIRED = 2;
+
+    /**
+     * This event type indicates that the licensed usage duration for keys in a session
+     * has expired.  The keys are no longer valid.
+     */
+    public static final int EVENT_KEY_EXPIRED = 3;
+
+    /**
+     * This event may indicate some specific vendor-defined condition, see your
+     * DRM provider documentation for details
+     */
+    public static final int EVENT_VENDOR_DEFINED = 4;
 
     private static final int DRM_EVENT = 200;
 
@@ -183,7 +247,7 @@
     }
 
     /*
-     * Called from native code when an interesting event happens.  This method
+     * This method is called from native code when an event occurs.  This method
      * just uses the EventHandler system to post the event back to the main app thread.
      * We use a weak reference to the original MediaPlayer object so that the native
      * code is safe from the object disappearing from underneath it.  (This is
@@ -203,82 +267,117 @@
     }
 
     /**
-     *  Open a new session with the MediaDrm object.  A session ID is returned.
+     * Open a new session with the MediaDrm object.  A session ID is returned.
      */
-    public native byte[] openSession() throws MediaDrmException;
+    public native byte[] openSession();
 
     /**
-     *  Close a session on the MediaDrm object that was previously opened
-     *  with {@link #openSession}.
+     * Close a session on the MediaDrm object that was previously opened
+     * with {@link #openSession}.
      */
-    public native void closeSession(byte[] sessionId) throws MediaDrmException;
+    public native void closeSession(byte[] sessionId);
 
-    public static final int MEDIA_DRM_KEY_TYPE_STREAMING = 1;
-    public static final int MEDIA_DRM_KEY_TYPE_OFFLINE = 2;
+    /**
+     * This key request type species that the keys will be for online use, they will
+     * not be saved to the device for subsequent use when the device is not connected
+     * to a network.
+     */
+    public static final int KEY_TYPE_STREAMING = 1;
 
-    public final class KeyRequest {
-        public KeyRequest() {}
-        public byte[] data;
-        public String defaultUrl;
+    /**
+     * This key request type specifies that the keys will be for offline use, they
+     * will be saved to the device for use when the device is not connected to a network.
+     */
+    public static final int KEY_TYPE_OFFLINE = 2;
+
+    /**
+     * This key request type specifies that previously saved offline keys should be released.
+     */
+    public static final int KEY_TYPE_RELEASE = 3;
+
+    /**
+     * Contains the opaque data an app uses to request keys from a license server
+     */
+    public final static class KeyRequest {
+        KeyRequest() {}
+
+        /**
+         * Get the opaque message data
+         */
+        public byte[] getData() { return mData; }
+
+        /**
+         * Get the default URL to use when sending the key request message to a
+         * server, if known.  The app may prefer to use a different license
+         * server URL from other sources.
+         */
+        public String getDefaultUrl() { return mDefaultUrl; }
+
+        private byte[] mData;
+        private String mDefaultUrl;
     };
 
     /**
-     * A key request/response exchange occurs between the app and a license
-     * server to obtain the keys to decrypt encrypted content.  getKeyRequest()
-     * is used to obtain an opaque key request byte array that is delivered to the
-     * license server.  The opaque key request byte array is returned in
-     * KeyRequest.data.  The recommended URL to deliver the key request to is
+     * A key request/response exchange occurs between the app and a license server
+     * to obtain or release keys used to decrypt encrypted content.
+     * <p>
+     * getKeyRequest() is used to obtain an opaque key request byte array that is
+     * delivered to the license server.  The opaque key request byte array is returned
+     * in KeyRequest.data.  The recommended URL to deliver the key request to is
      * returned in KeyRequest.defaultUrl.
-     *
+     * <p>
      * After the app has received the key request response from the server,
      * it should deliver to the response to the DRM engine plugin using the method
      * {@link #provideKeyResponse}.
      *
-     * @param sessonId the session ID for the drm session
+     * @param scope may be a sessionId or a keySetId, depending on the specified keyType.
+     * When the keyType is KEY_TYPE_STREAMING or KEY_TYPE_OFFLINE,
+     * scope should be set to the sessionId the keys will be provided to.  When the keyType
+     * is KEY_TYPE_RELEASE, scope should be set to the keySetId of the keys
+     * being released. Releasing keys from a device invalidates them for all sessions.
      * @param init container-specific data, its meaning is interpreted based on the
      * mime type provided in the mimeType parameter.  It could contain, for example,
      * the content ID, key ID or other data obtained from the content metadata that is
-     * required in generating the key request.
+     * required in generating the key request. init may be null when keyType is
+     * KEY_TYPE_RELEASE.
      * @param mimeType identifies the mime type of the content
-     * @param keyType specifes if the request is for streaming or offline content
+     * @param keyType specifes the type of the request. The request may be to acquire
+     * keys for streaming or offline content, or to release previously acquired
+     * keys, which are identified by a keySetId.
      * @param optionalParameters are included in the key request message to
      * allow a client application to provide additional message parameters to the server.
      */
-    public native KeyRequest getKeyRequest(byte[] sessionId, byte[] init,
+    public native KeyRequest getKeyRequest(byte[] scope, byte[] init,
                                            String mimeType, int keyType,
-                                           HashMap<String, String> optionalParameters)
-        throws MediaDrmException;
+                                           HashMap<String, String> optionalParameters);
+
 
     /**
      * A key response is received from the license server by the app, then it is
      * provided to the DRM engine plugin using provideKeyResponse. The byte array
      * returned is a keySetId that can be used to later restore the keys to a new
-     * session with the method {@link restoreKeys}, enabling offline key use.
+     * session with the method {@link #restoreKeys}, enabling offline key use.
      *
      * @param sessionId the session ID for the DRM session
      * @param response the byte array response from the server
      */
-    public native byte[] provideKeyResponse(byte[] sessionId, byte[] response)
-        throws MediaDrmException;
+    public native byte[] provideKeyResponse(byte[] sessionId, byte[] response);
 
     /**
      * Restore persisted offline keys into a new session.  keySetId identifies the
-     * keys to load, obtained from a prior call to {@link provideKeyResponse}.
+     * keys to load, obtained from a prior call to {@link #provideKeyResponse}.
      *
      * @param sessionId the session ID for the DRM session
      * @param keySetId identifies the saved key set to restore
      */
-    public native void restoreKeys(byte[] sessionId, byte[] keySetId)
-        throws MediaDrmException;
+    public native void restoreKeys(byte[] sessionId, byte[] keySetId);
 
     /**
-     * Remove the persisted keys associated with an offline license.  Keys are persisted
-     * when {@link provideKeyResponse} is called with keys obtained from the method
-     * {@link getKeyRequest} using keyType = MEDIA_DRM_KEY_TYPE_OFFLINE.
+     * Remove the current keys from a session.
      *
-     * @param keySetId identifies the saved key set to remove
+     * @param sessionId the session ID for the DRM session
      */
-    public native void removeKeys(byte[] keySetId) throws MediaDrmException;
+    public native void removeKeys(byte[] sessionId);
 
     /**
      * Request an informative description of the key status for the session.  The status is
@@ -289,25 +388,41 @@
      *
      * @param sessionId the session ID for the DRM session
      */
-    public native HashMap<String, String> queryKeyStatus(byte[] sessionId)
-        throws MediaDrmException;
+    public native HashMap<String, String> queryKeyStatus(byte[] sessionId);
 
-    public final class ProvisionRequest {
-        public ProvisionRequest() {}
-        public byte[] data;
-        public String defaultUrl;
+    /**
+     * Contains the opaque data an app uses to request a certificate from a provisioning
+     * server
+     */
+    public final static class ProvisionRequest {
+        ProvisionRequest() {}
+
+        /**
+         * Get the opaque message data
+         */
+        public byte[] getData() { return mData; }
+
+        /**
+         * Get the default URL to use when sending the provision request
+         * message to a server, if known. The app may prefer to use a different
+         * provisioning server URL obtained from other sources.
+         */
+        public String getDefaultUrl() { return mDefaultUrl; }
+
+        private byte[] mData;
+        private String mDefaultUrl;
     }
 
     /**
      * A provision request/response exchange occurs between the app and a provisioning
      * server to retrieve a device certificate.  If provisionining is required, the
-     * MEDIA_DRM_EVENT_PROVISION_REQUIRED event will be sent to the event handler.
+     * EVENT_PROVISION_REQUIRED event will be sent to the event handler.
      * getProvisionRequest is used to obtain the opaque provision request byte array that
      * should be delivered to the provisioning server. The provision request byte array
      * is returned in ProvisionRequest.data. The recommended URL to deliver the provision
      * request to is returned in ProvisionRequest.defaultUrl.
      */
-    public native ProvisionRequest getProvisionRequest() throws MediaDrmException;
+    public native ProvisionRequest getProvisionRequest();
 
     /**
      * After a provision response is received by the app, it is provided to the DRM
@@ -316,92 +431,91 @@
      * @param response the opaque provisioning response byte array to provide to the
      * DRM engine plugin.
      */
-    public native void provideProvisionResponse(byte[] response)
-        throws MediaDrmException;
+    public native void provideProvisionResponse(byte[] response);
 
     /**
-     * A means of enforcing the contractual requirement for a concurrent stream limit
-     * per subscriber across devices is provided via SecureStop.  SecureStop is a means
-     * of securely monitoring the lifetime of sessions. Since playback on a device can
-     * be interrupted due to reboot, power failure, etc. a means of persisting the
-     * lifetime information on the device is needed.
-     *
-     * A signed version of the sessionID is written to persistent storage on the device
-     * when each MediaCrypto object is created. The sessionID is signed by the device
-     * private key to prevent tampering.
-     *
+     * A means of enforcing limits on the number of concurrent streams per subscriber
+     * across devices is provided via SecureStop. This is achieved by securely
+     * monitoring the lifetime of sessions.
+     * <p>
+     * Information from the server related to the current playback session is written
+     * to persistent storage on the device when each MediaCrypto object is created.
+     * <p>
      * In the normal case, playback will be completed, the session destroyed and the
-     * Secure Stops will be queried. The App queries secure stops and forwards the
+     * Secure Stops will be queried. The app queries secure stops and forwards the
      * secure stop message to the server which verifies the signature and notifies the
      * server side database that the session destruction has been confirmed. The persisted
      * record on the client is only removed after positive confirmation that the server
      * received the message using releaseSecureStops().
      */
-    public native List<byte[]> getSecureStops() throws MediaDrmException;
+    public native List<byte[]> getSecureStops();
 
 
     /**
      * Process the SecureStop server response message ssRelease.  After authenticating
-     * the message, remove the SecureStops identiied in the response.
+     * the message, remove the SecureStops identified in the response.
      *
      * @param ssRelease the server response indicating which secure stops to release
      */
-    public native void releaseSecureStops(byte[] ssRelease)
-        throws MediaDrmException;
+    public native void releaseSecureStops(byte[] ssRelease);
 
 
     /**
-     * Read a DRM engine plugin property value, given the property name string.  There are
-     * several forms of property access functions, depending on the data type returned.
-     *
+     * String property name: identifies the maker of the DRM engine plugin
+     */
+    public static final String PROPERTY_VENDOR = "vendor";
+
+    /**
+     * String property name: identifies the version of the DRM engine plugin
+     */
+    public static final String PROPERTY_VERSION = "version";
+
+    /**
+     * String property name: describes the DRM engine plugin
+     */
+    public static final String PROPERTY_DESCRIPTION = "description";
+
+    /**
+     * String property name: a comma-separated list of cipher and mac algorithms
+     * supported by CryptoSession.  The list may be empty if the DRM engine
+     * plugin does not support CryptoSession operations.
+     */
+    public static final String PROPERTY_ALGORITHM = "algorithm";
+
+    /**
+     * Read a DRM engine plugin String property value, given the property name string.
+     * <p>
      * Standard fields names are:
-     *   vendor         String - identifies the maker of the DRM engine plugin
-     *   version        String - identifies the version of the DRM engine plugin
-     *   description    String - describes the DRM engine plugin
-     *   deviceUniqueId byte[] - The device unique identifier is established during device
-     *                           provisioning and provides a means of uniquely identifying
-     *                           each device
-     *   algorithms     String - a comma-separate list of cipher and mac algorithms supported
-     *                           by CryptoSession.  The list may be empty if the DRM engine
-     *                           plugin does not support CryptoSession operations.
+     * {@link #PROPERTY_VENDOR}, {@link #PROPERTY_VERSION},
+     * {@link #PROPERTY_DESCRIPTION}, {@link #PROPERTY_ALGORITHM}
      */
-    public native String getPropertyString(String propertyName)
-        throws MediaDrmException;
+    public native String getPropertyString(String propertyName);
 
-    public native byte[] getPropertyByteArray(String propertyName)
-        throws MediaDrmException;
 
     /**
-     * Write a DRM engine plugin property value.  There are several forms of
-     * property setting functions, depending on the data type being set.
+     * The device unique identifier is established during device provisioning and
+     * provides a means of uniquely identifying each device
      */
-    public native void setPropertyString(String propertyName, String value)
-        throws MediaDrmException;
-
-    public native void setPropertyByteArray(String propertyName, byte[] value)
-        throws MediaDrmException;
+    public static final String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId";
 
     /**
-     * In addition to supporting decryption of DASH Common Encrypted Media, the
-     * MediaDrm APIs provide the ability to securely deliver session keys from
-     * an operator's session key server to a client device, based on the factory-installed
-     * root of trust, and provide the ability to do encrypt, decrypt, sign and verify
-     * with the session key on arbitrary user data.
-     *
-     * The CryptoSession class implements generic encrypt/decrypt/sign/verify methods
-     * based on the established session keys.  These keys are exchanged using the
-     * getKeyRequest/provideKeyResponse methods.
-     *
-     * Applications of this capability could include securing various types of
-     * purchased or private content, such as applications, books and other media,
-     * photos or media delivery protocols.
-     *
-     * Operators can create session key servers that are functionally similar to a
-     * license key server, except that instead of receiving license key requests and
-     * providing encrypted content keys which are used specifically to decrypt A/V media
-     * content, the session key server receives session key requests and provides
-     * encrypted session keys which can be used for general purpose crypto operations.
+     * Read a DRM engine plugin byte array property value, given the property name string.
+     * <p>
+     * Standard fields names are {@link #PROPERTY_DEVICE_UNIQUE_ID}
      */
+    public native byte[] getPropertyByteArray(String propertyName);
+
+
+    /**
+     * Set a DRM engine plugin String property value.
+     */
+    public native void setPropertyString(String propertyName, String value);
+
+    /**
+     * Set a DRM engine plugin byte array property value.
+     */
+    public native void setPropertyByteArray(String propertyName, byte[] value);
+
 
     private static final native void setCipherAlgorithmNative(MediaDrm drm, byte[] sessionId,
                                                               String algorithm);
@@ -422,61 +536,112 @@
                                                      byte[] keyId, byte[] message,
                                                      byte[] signature);
 
+    /**
+     * In addition to supporting decryption of DASH Common Encrypted Media, the
+     * MediaDrm APIs provide the ability to securely deliver session keys from
+     * an operator's session key server to a client device, based on the factory-installed
+     * root of trust, and then perform encrypt, decrypt, sign and verify operations
+     * with the session key on arbitrary user data.
+     * <p>
+     * The CryptoSession class implements generic encrypt/decrypt/sign/verify methods
+     * based on the established session keys.  These keys are exchanged using the
+     * getKeyRequest/provideKeyResponse methods.
+     * <p>
+     * Applications of this capability could include securing various types of
+     * purchased or private content, such as applications, books and other media,
+     * photos or media delivery protocols.
+     * <p>
+     * Operators can create session key servers that are functionally similar to a
+     * license key server, except that instead of receiving license key requests and
+     * providing encrypted content keys which are used specifically to decrypt A/V media
+     * content, the session key server receives session key requests and provides
+     * encrypted session keys which can be used for general purpose crypto operations.
+     * <p>
+     * A CryptoSession is obtained using {@link #getCryptoSession}
+     */
     public final class CryptoSession {
         private MediaDrm mDrm;
         private byte[] mSessionId;
 
-        /**
-         * Construct a CryptoSession which can be used to encrypt, decrypt,
-         * sign and verify messages or data using the session keys established
-         * for the session using methods {@link getKeyRequest} and
-         * {@link provideKeyResponse} using a session key server.
-         *
-         * @param sessionId the session ID for the session containing keys
-         * to be used for encrypt, decrypt, sign and/or verify
-         *
-         * @param cipherAlgorithm the algorithm to use for encryption and
-         * decryption ciphers. The algorithm string conforms to JCA Standard
-         * Names for Cipher Transforms and is case insensitive.  For example
-         * "AES/CBC/PKCS5Padding".
-         *
-         * @param macAlgorithm the algorithm to use for sign and verify
-         * The algorithm string conforms to JCA Standard Names for Mac
-         * Algorithms and is case insensitive.  For example "HmacSHA256".
-         *
-         * The list of supported algorithms for a DRM engine plugin can be obtained
-         * using the method {@link getPropertyString("algorithms")}
-         */
-
-        public CryptoSession(MediaDrm drm, byte[] sessionId,
-                             String cipherAlgorithm, String macAlgorithm)
-            throws MediaDrmException {
+        CryptoSession(MediaDrm drm, byte[] sessionId,
+                      String cipherAlgorithm, String macAlgorithm)
+        {
             mSessionId = sessionId;
             mDrm = drm;
             setCipherAlgorithmNative(drm, sessionId, cipherAlgorithm);
             setMacAlgorithmNative(drm, sessionId, macAlgorithm);
         }
 
+        /**
+         * Encrypt data using the CryptoSession's cipher algorithm
+         *
+         * @param keyid specifies which key to use
+         * @param input the data to encrypt
+         * @param iv the initialization vector to use for the cipher
+         */
         public byte[] encrypt(byte[] keyid, byte[] input, byte[] iv) {
             return encryptNative(mDrm, mSessionId, keyid, input, iv);
         }
 
+        /**
+         * Decrypt data using the CryptoSessions's cipher algorithm
+         *
+         * @param keyid specifies which key to use
+         * @param input the data to encrypt
+         * @param iv the initialization vector to use for the cipher
+         */
         public byte[] decrypt(byte[] keyid, byte[] input, byte[] iv) {
             return decryptNative(mDrm, mSessionId, keyid, input, iv);
         }
 
+        /**
+         * Sign data using the CryptoSessions's mac algorithm.
+         *
+         * @param keyid specifies which key to use
+         * @param message the data for which a signature is to be computed
+         */
         public byte[] sign(byte[] keyid, byte[] message) {
             return signNative(mDrm, mSessionId, keyid, message);
         }
+
+        /**
+         * Verify a signature using the CryptoSessions's mac algorithm. Return true
+         * if the signatures match, false if they do no.
+         *
+         * @param keyid specifies which key to use
+         * @param message the data to verify
+         * @param signature the reference signature which will be compared with the
+         *        computed signature
+         */
         public boolean verify(byte[] keyid, byte[] message, byte[] signature) {
             return verifyNative(mDrm, mSessionId, keyid, message, signature);
         }
     };
 
+    /**
+     * Obtain a CryptoSession object which can be used to encrypt, decrypt,
+     * sign and verify messages or data using the session keys established
+     * for the session using methods {@link #getKeyRequest} and
+     * {@link #provideKeyResponse} using a session key server.
+     *
+     * @param sessionId the session ID for the session containing keys
+     * to be used for encrypt, decrypt, sign and/or verify
+     * @param cipherAlgorithm the algorithm to use for encryption and
+     * decryption ciphers. The algorithm string conforms to JCA Standard
+     * Names for Cipher Transforms and is case insensitive.  For example
+     * "AES/CBC/NoPadding".
+     * @param macAlgorithm the algorithm to use for sign and verify
+     * The algorithm string conforms to JCA Standard Names for Mac
+     * Algorithms and is case insensitive.  For example "HmacSHA256".
+     * <p>
+     * The list of supported algorithms for a DRM engine plugin can be obtained
+     * using the method {@link #getPropertyString} with the property name
+     * "algorithms".
+     */
     public CryptoSession getCryptoSession(byte[] sessionId,
                                           String cipherAlgorithm,
                                           String macAlgorithm)
-        throws MediaDrmException {
+    {
         return new CryptoSession(this, sessionId, cipherAlgorithm, macAlgorithm);
     }
 
@@ -488,8 +653,7 @@
     public native final void release();
     private static native final void native_init();
 
-    private native final void native_setup(Object mediadrm_this, byte[] uuid)
-        throws MediaDrmException;
+    private native final void native_setup(Object mediadrm_this, byte[] uuid);
 
     private native final void native_finalize();
 
diff --git a/media/java/android/media/MediaDrmException.java b/media/java/android/media/MediaDrmException.java
index 6f81f90..d6f5ff4 100644
--- a/media/java/android/media/MediaDrmException.java
+++ b/media/java/android/media/MediaDrmException.java
@@ -19,8 +19,6 @@
 /**
  * Exception thrown if MediaDrm object could not be instantiated for
  * whatever reason.
- *
- * @hide -- don't expose yet
  */
 public final class MediaDrmException extends Exception {
     public MediaDrmException(String detailMessage) {
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 93bcf03..f77ddc4 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -65,6 +65,7 @@
 public class RemoteControlClient
 {
     private final static String TAG = "RemoteControlClient";
+    private final static boolean DEBUG = false;
 
     /**
      * Playback state of a RemoteControlClient which is stopped.
@@ -219,7 +220,7 @@
     public final static int PLAYBACKINFO_USES_STREAM = 5;
 
     //==========================================
-    // Public flags for the supported transport control capabililities
+    // Public flags for the supported transport control capabilities
     /**
      * Flag indicating a RemoteControlClient makes use of the "previous" media key.
      *
@@ -277,14 +278,12 @@
      */
     public final static int FLAG_KEY_MEDIA_NEXT = 1 << 7;
     /**
-     * @hide
-     * TODO un-hide and add in javadoc of setTransportControlFlags(int)
      * Flag indicating a RemoteControlClient can receive changes in the media playback position
-     * through the {@link #OnPlaybackPositionUpdateListener} interface. This flag must be set
+     * through the {@link OnPlaybackPositionUpdateListener} interface. This flag must be set
      * in order for components that display the RemoteControlClient information, to display and
      * let the user control media playback position.
      * @see #setTransportControlFlags(int)
-     * @see #setPlaybackPositionProvider(PlaybackPositionProvider)
+     * @see #setOnGetPlaybackPositionListener(OnGetPlaybackPositionListener)
      * @see #setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener)
      */
     public final static int FLAG_KEY_MEDIA_POSITION_UPDATE = 1 << 8;
@@ -607,8 +606,6 @@
     }
 
     /**
-     * @hide
-     * TODO un-hide
      * Sets the current playback state and the matching media position for the current playback
      *   speed.
      * @param state The current playback state, one of the following values:
@@ -646,6 +643,57 @@
                 sendPlaybackState_syncCacheLock();
                 // update AudioService
                 sendAudioServiceNewPlaybackState_syncCacheLock();
+
+                // handle automatic playback position refreshes
+                if (mEventHandler == null) {
+                    return;
+                }
+                mEventHandler.removeMessages(MSG_POSITION_DRIFT_CHECK);
+                if (timeInMs == PLAYBACK_POSITION_INVALID) {
+                    // this playback state refresh has no known playback position, it's no use
+                    // trying to see if there is any drift at this point
+                    // (this also bypasses this mechanism for older apps that use the old
+                    //  setPlaybackState(int) API)
+                    return;
+                }
+                if (playbackPositionShouldMove(mPlaybackState)) {
+                    // playback position moving, schedule next position drift check
+                    mEventHandler.sendMessageDelayed(
+                            mEventHandler.obtainMessage(MSG_POSITION_DRIFT_CHECK),
+                            getCheckPeriodFromSpeed(playbackSpeed));
+                }
+            }
+        }
+    }
+
+    private void onPositionDriftCheck() {
+        if (DEBUG) { Log.d(TAG, "onPositionDriftCheck()"); }
+        synchronized(mCacheLock) {
+            if ((mEventHandler == null) || (mPositionProvider == null)) {
+                return;
+            }
+            if ((mPlaybackPositionMs == PLAYBACK_POSITION_INVALID) || (mPlaybackSpeed == 0.0f)) {
+                if (DEBUG) { Log.d(TAG, " no position or 0 speed, no check needed"); }
+                return;
+            }
+            long estPos = mPlaybackPositionMs + (long)
+                    ((SystemClock.elapsedRealtime() - mPlaybackStateChangeTimeMs) / mPlaybackSpeed);
+            long actPos = mPositionProvider.onGetPlaybackPosition();
+            if (actPos >= 0) {
+                if (Math.abs(estPos - actPos) > POSITION_DRIFT_MAX_MS) {
+                    // drift happened, report the new position
+                    if (DEBUG) { Log.w(TAG, " drift detected: actual=" +actPos +"  est=" +estPos); }
+                    setPlaybackState(mPlaybackState, actPos, mPlaybackSpeed);
+                } else {
+                    if (DEBUG) { Log.d(TAG, " no drift: actual=" + actPos +"  est=" + estPos); }
+                    // no drift, schedule the next drift check
+                    mEventHandler.sendMessageDelayed(
+                            mEventHandler.obtainMessage(MSG_POSITION_DRIFT_CHECK),
+                            getCheckPeriodFromSpeed(mPlaybackSpeed));
+                }
+            } else {
+                // invalid position (negative value), can't check for drift
+                mEventHandler.removeMessages(MSG_POSITION_DRIFT_CHECK);
             }
         }
     }
@@ -660,7 +708,8 @@
      *      {@link #FLAG_KEY_MEDIA_PAUSE},
      *      {@link #FLAG_KEY_MEDIA_STOP},
      *      {@link #FLAG_KEY_MEDIA_FAST_FORWARD},
-     *      {@link #FLAG_KEY_MEDIA_NEXT}
+     *      {@link #FLAG_KEY_MEDIA_NEXT},
+     *      {@link #FLAG_KEY_MEDIA_POSITION_UPDATE}
      */
     public void setTransportControlFlags(int transportControlFlags) {
         synchronized(mCacheLock) {
@@ -673,8 +722,6 @@
     }
 
     /**
-     * @hide
-     * TODO un-hide
      * Interface definition for a callback to be invoked when the media playback position is
      * requested to be updated.
      * @see RemoteControlClient#FLAG_KEY_MEDIA_POSITION_UPDATE
@@ -684,7 +731,7 @@
          * Called on the implementer to notify it that the playback head should be set at the given
          * position. If the position can be changed from its current value, the implementor of
          * the interface must also update the playback position using
-         * {@link RemoteControlClient#setPlaybackState(int, long, int)} to reflect the actual new
+         * {@link #setPlaybackState(int, long, float)} to reflect the actual new
          * position being used, regardless of whether it differs from the requested position.
          * Failure to do so would cause the system to not know the new actual playback position,
          * and user interface components would fail to show the user where playback resumed after
@@ -695,30 +742,26 @@
     }
 
     /**
-     * @hide
-     * TODO un-hide
      * Interface definition for a callback to be invoked when the media playback position is
      * queried.
      * @see RemoteControlClient#FLAG_KEY_MEDIA_POSITION_UPDATE
      */
-    public interface PlaybackPositionProvider {
+    public interface OnGetPlaybackPositionListener {
         /**
          * Called on the implementer of the interface to query the current playback position.
          * @return a negative value if the current playback position (or the last valid playback
          *     position) is not known, or a zero or positive value expressed in ms indicating the
          *     current position, or the last valid known position.
          */
-        long getPlaybackPosition();
+        long onGetPlaybackPosition();
     }
 
     /**
-     * @hide
-     * TODO un-hide
      * Sets the listener to be called whenever the media playback position is requested
      * to be updated.
      * Notifications will be received in the same thread as the one in which RemoteControlClient
      * was created.
-     * @param l
+     * @param l the position update listener to be called
      */
     public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener l) {
         synchronized(mCacheLock) {
@@ -737,14 +780,12 @@
     }
 
     /**
-     * @hide
-     * TODO un-hide
      * Sets the listener to be called whenever the media current playback position is needed.
      * Queries will be received in the same thread as the one in which RemoteControlClient
      * was created.
-     * @param l
+     * @param l the listener to be called to retrieve the playback position
      */
-    public void setPlaybackPositionProvider(PlaybackPositionProvider l) {
+    public void setOnGetPlaybackPositionListener(OnGetPlaybackPositionListener l) {
         synchronized(mCacheLock) {
             int oldCapa = mPlaybackPositionCapabilities;
             if (l != null) {
@@ -757,6 +798,14 @@
                 // tell RCDs that this RCC's playback position capabilities have changed
                 sendTransportControlInfo_syncCacheLock();
             }
+            if ((mPositionProvider != null) && (mEventHandler != null)
+                    && playbackPositionShouldMove(mPlaybackState)) {
+                // playback position is already moving, but now we have a position provider,
+                // so schedule a drift check right now
+                mEventHandler.sendMessageDelayed(
+                        mEventHandler.obtainMessage(MSG_POSITION_DRIFT_CHECK),
+                        0 /*check now*/);
+            }
         }
     }
 
@@ -942,7 +991,7 @@
     /**
      * Provider registered by user of RemoteControlClient to provide the current playback position.
      */
-    private PlaybackPositionProvider mPositionProvider;
+    private OnGetPlaybackPositionListener mPositionProvider;
     /**
      * The current remote control client generation ID across the system, as known by this object
      */
@@ -1010,7 +1059,7 @@
             if (mEventHandler != null) {
                 // signal new client
                 mEventHandler.removeMessages(MSG_NEW_INTERNAL_CLIENT_GEN);
-                mEventHandler.dispatchMessage(
+                mEventHandler.sendMessage(
                         mEventHandler.obtainMessage(MSG_NEW_INTERNAL_CLIENT_GEN,
                                 /*arg1*/ generationId, /*arg2, ignored*/ 0));
                 // send the information
@@ -1018,12 +1067,12 @@
                 mEventHandler.removeMessages(MSG_REQUEST_METADATA);
                 mEventHandler.removeMessages(MSG_REQUEST_TRANSPORTCONTROL);
                 mEventHandler.removeMessages(MSG_REQUEST_ARTWORK);
-                mEventHandler.dispatchMessage(
+                mEventHandler.sendMessage(
                         mEventHandler.obtainMessage(MSG_REQUEST_PLAYBACK_STATE));
-                mEventHandler.dispatchMessage(
+                mEventHandler.sendMessage(
                         mEventHandler.obtainMessage(MSG_REQUEST_TRANSPORTCONTROL));
-                mEventHandler.dispatchMessage(mEventHandler.obtainMessage(MSG_REQUEST_METADATA));
-                mEventHandler.dispatchMessage(mEventHandler.obtainMessage(MSG_REQUEST_ARTWORK));
+                mEventHandler.sendMessage(mEventHandler.obtainMessage(MSG_REQUEST_METADATA));
+                mEventHandler.sendMessage(mEventHandler.obtainMessage(MSG_REQUEST_ARTWORK));
             }
         }
 
@@ -1031,7 +1080,7 @@
             // only post messages, we can't block here
             if (mEventHandler != null) {
                 mEventHandler.removeMessages(MSG_NEW_CURRENT_CLIENT_GEN);
-                mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
+                mEventHandler.sendMessage(mEventHandler.obtainMessage(
                         MSG_NEW_CURRENT_CLIENT_GEN, clientGeneration, 0/*ignored*/));
             }
         }
@@ -1039,7 +1088,7 @@
         public void plugRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
             // only post messages, we can't block here
             if ((mEventHandler != null) && (rcd != null)) {
-                mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
+                mEventHandler.sendMessage(mEventHandler.obtainMessage(
                         MSG_PLUG_DISPLAY, w, h, rcd));
             }
         }
@@ -1047,7 +1096,7 @@
         public void unplugRemoteControlDisplay(IRemoteControlDisplay rcd) {
             // only post messages, we can't block here
             if ((mEventHandler != null) && (rcd != null)) {
-                mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
+                mEventHandler.sendMessage(mEventHandler.obtainMessage(
                         MSG_UNPLUG_DISPLAY, rcd));
             }
         }
@@ -1055,7 +1104,7 @@
         public void setBitmapSizeForDisplay(IRemoteControlDisplay rcd, int w, int h) {
             // only post messages, we can't block here
             if ((mEventHandler != null) && (rcd != null)) {
-                mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
+                mEventHandler.sendMessage(mEventHandler.obtainMessage(
                         MSG_UPDATE_DISPLAY_ARTWORK_SIZE, w, h, rcd));
             }
         }
@@ -1064,7 +1113,7 @@
             // only post messages, we can't block here
             if (mEventHandler != null) {
                 mEventHandler.removeMessages(MSG_SEEK_TO);
-                mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
+                mEventHandler.sendMessage(mEventHandler.obtainMessage(
                         MSG_SEEK_TO, generationId /* arg1 */, 0 /* arg2, ignored */,
                         new Long(timeMs)));
             }
@@ -1110,6 +1159,7 @@
     private final static int MSG_UNPLUG_DISPLAY = 8;
     private final static int MSG_UPDATE_DISPLAY_ARTWORK_SIZE = 9;
     private final static int MSG_SEEK_TO = 10;
+    private final static int MSG_POSITION_DRIFT_CHECK = 11;
 
     private class EventHandler extends Handler {
         public EventHandler(RemoteControlClient rcc, Looper looper) {
@@ -1156,6 +1206,10 @@
                     break;
                 case MSG_SEEK_TO:
                     onSeekTo(msg.arg1, ((Long)msg.obj).longValue());
+                    break;
+                case MSG_POSITION_DRIFT_CHECK:
+                    onPositionDriftCheck();
+                    break;
                 default:
                     Log.e(TAG, "Unknown event " + msg.what + " in RemoteControlClient handler");
             }
@@ -1450,4 +1504,57 @@
             return false;
         }
     }
+
+    /**
+     * Returns whether, for the given playback state, the playback position is expected to
+     * be changing.
+     * @param playstate the playback state to evaluate
+     * @return true during any form of playback, false if it's not playing anything while in this
+     *     playback state
+     */
+    private static boolean playbackPositionShouldMove(int playstate) {
+        switch(playstate) {
+            case PLAYSTATE_STOPPED:
+            case PLAYSTATE_PAUSED:
+            case PLAYSTATE_BUFFERING:
+            case PLAYSTATE_ERROR:
+            case PLAYSTATE_SKIPPING_FORWARDS:
+            case PLAYSTATE_SKIPPING_BACKWARDS:
+                return false;
+            case PLAYSTATE_PLAYING:
+            case PLAYSTATE_FAST_FORWARDING:
+            case PLAYSTATE_REWINDING:
+            default:
+                return true;
+        }
+    }
+
+    /**
+     * Period for playback position drift checks, 15s when playing at 1x or slower.
+     */
+    private final static long POSITION_REFRESH_PERIOD_PLAYING_MS = 15000;
+    /**
+     * Minimum period for playback position drift checks, never more often when every 2s, when
+     * fast forwarding or rewinding.
+     */
+    private final static long POSITION_REFRESH_PERIOD_MIN_MS = 2000;
+    /**
+     * The value above which the difference between client-reported playback position and
+     * estimated position is considered a drift.
+     */
+    private final static long POSITION_DRIFT_MAX_MS = 500;
+    /**
+     * Compute the period at which the estimated playback position should be compared against the
+     * actual playback position. Is a funciton of playback speed.
+     * @param speed 1.0f is normal playback speed
+     * @return the period in ms
+     */
+    private static long getCheckPeriodFromSpeed(float speed) {
+        if (Math.abs(speed) <= 1.0f) {
+            return POSITION_REFRESH_PERIOD_PLAYING_MS;
+        } else {
+            return Math.max((long)(POSITION_REFRESH_PERIOD_PLAYING_MS / Math.abs(speed)),
+                    POSITION_REFRESH_PERIOD_MIN_MS);
+        }
+    }
 }
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index c32ba9d..d1b499e 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -30,6 +30,7 @@
 #include <media/IDrm.h>
 #include <media/IMediaPlayerService.h>
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaErrors.h>
 
 namespace android {
 
@@ -191,10 +192,62 @@
 static bool throwExceptionAsNecessary(
         JNIEnv *env, status_t err, const char *msg = NULL) {
 
+    const char *drmMessage = NULL;
+
+    switch(err) {
+    case ERROR_DRM_UNKNOWN:
+        drmMessage = "General DRM error";
+        break;
+    case ERROR_DRM_NO_LICENSE:
+        drmMessage = "No license";
+        break;
+    case ERROR_DRM_LICENSE_EXPIRED:
+        drmMessage = "License expired";
+        break;
+    case ERROR_DRM_SESSION_NOT_OPENED:
+        drmMessage = "Session not opened";
+        break;
+    case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED:
+        drmMessage = "Not initialized";
+        break;
+    case ERROR_DRM_DECRYPT:
+        drmMessage = "Decrypt error";
+        break;
+    case ERROR_DRM_CANNOT_HANDLE:
+        drmMessage = "Unsupported scheme or data format";
+        break;
+    case ERROR_DRM_TAMPER_DETECTED:
+        drmMessage = "Invalid state";
+        break;
+    case ERROR_DRM_NOT_PROVISIONED:
+        drmMessage = "Not provisioned";
+        break;
+    case ERROR_DRM_DEVICE_REVOKED:
+        drmMessage = "Device revoked";
+        break;
+    default:
+        break;
+    }
+
+    String8 vendorMessage;
+    if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) {
+        vendorMessage.format("DRM vendor-defined error: %d", err);
+        drmMessage = vendorMessage.string();
+    }
+
     if (err == BAD_VALUE) {
         jniThrowException(env, "java/lang/IllegalArgumentException", msg);
         return true;
     } else if (err != OK) {
+        String8 errbuf;
+        if (drmMessage != NULL) {
+            if (msg == NULL) {
+                msg = drmMessage;
+            } else {
+                errbuf.format("%s: %s", msg, drmMessage);
+                msg = errbuf.string();
+            }
+        }
         jniThrowException(env, "java/lang/IllegalStateException", msg);
         return true;
     }
@@ -458,22 +511,22 @@
                          "(Ljava/lang/Object;IILjava/lang/Object;)V");
 
     jfieldID field;
-    GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_PROVISION_REQUIRED", "I");
+    GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
     gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
-    GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_KEY_REQUIRED", "I");
+    GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
     gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
-    GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_KEY_EXPIRED", "I");
+    GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
     gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
-    GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_VENDOR_DEFINED", "I");
+    GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
     gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
 
     FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
-    GET_FIELD_ID(gFields.keyRequest.data, clazz, "data", "[B");
-    GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "defaultUrl", "Ljava/lang/String;");
+    GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
+    GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
 
     FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
-    GET_FIELD_ID(gFields.provisionRequest.data, clazz, "data", "[B");
-    GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "defaultUrl", "Ljava/lang/String;");
+    GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
+    GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
 
     FIND_CLASS(clazz, "java/util/ArrayList");
     GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
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/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index ab7ceb6..dac3506 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -184,7 +184,6 @@
     private int mDebugFlags;
     private int mEGLContextClientVersion;
     private boolean mPreserveEGLContextOnPause;
-    private int mUserRenderMode;
 
     /**
      * The renderer only renders
@@ -246,7 +245,7 @@
             if (mGLThread != null) {
                 // GLThread may still be running if this view was never
                 // attached to a window.
-                mGLThread.requestExitAndWait();
+                mGLThread.quitSafely();
             }
         } finally {
             super.finalize();
@@ -258,7 +257,6 @@
         // underlying surface is created and destroyed
         SurfaceHolder holder = getHolder();
         holder.addCallback(this);
-        mUserRenderMode = RENDERMODE_CONTINUOUSLY;
     }
 
     /**
@@ -516,7 +514,6 @@
             default:
                 throw new IllegalArgumentException("renderMode");
         }
-        mUserRenderMode = renderMode;
         mGLThread.setRenderMode(renderMode);
     }
 
@@ -528,7 +525,7 @@
      * @see #RENDERMODE_WHEN_DIRTY
      */
     public int getRenderMode() {
-        return mUserRenderMode;
+        return mGLThread.getRenderMode();
     }
 
     /**
@@ -608,9 +605,13 @@
         if (LOG_ATTACH_DETACH) {
             Log.d(TAG, "onAttachedToWindow reattach =" + mDetached);
         }
+
+        final int renderMode = mGLThread != null ?
+                mGLThread.mRenderMode : RENDERMODE_CONTINUOUSLY;
+
         if (mDetached && (mRenderer != null)) {
             mGLThread = new GLThread(mThisWeakRef);
-            mGLThread.setRenderMode(mUserRenderMode);
+            mGLThread.setRenderMode(renderMode);
             mGLThread.start();
         }
         mDetached = false;
@@ -627,7 +628,11 @@
             Log.d(TAG, "onDetachedFromWindow");
         }
         if (mGLThread != null) {
-            mGLThread.requestExitAndWait();
+            mGLThread.quitSafely();
+            try {
+                mGLThread.join();
+            } catch (InterruptedException ex) {
+            }
         }
         mDetached = true;
         super.onDetachedFromWindow();
@@ -1261,6 +1266,17 @@
         private Handler mGLHandler;
         private Choreographer mChoreographer;
 
+        // this runnable could be called often, so we keep an instance around
+        class GetRenderModeRunnable implements Runnable {
+            volatile public int renderMode;
+            @Override
+            public void run() {
+                renderMode = doGetRenderMode();
+            }
+        };
+
+        private final GetRenderModeRunnable mGetRenderModeRunnable = new GetRenderModeRunnable();
+
         /*
          * Set once at thread construction time, nulled out when the parent view is garbage
          * called. This weak reference allows the GLSurfaceView to be garbage collected while
@@ -1511,7 +1527,7 @@
             }
         }
 
-        private void doWindowResize(final int width, final int height) {
+        private void doWindowResize(int width, int height) {
             // we were not drawing yet. Update the window size and
             // state and attempt to draw a frame.
             mSizeChanged = (mWidth != width || mHeight != height);
@@ -1522,9 +1538,13 @@
             executeDraw();
         }
 
-        private void doSetRenderMode(final int renderMode) {
+        private void doSetRenderMode(int renderMode) {
             mRenderMode = renderMode;
-            requestRender();
+        }
+
+
+        private int doGetRenderMode() {
+            return mRenderMode;
         }
 
         /*
@@ -1607,12 +1627,9 @@
             }, 0);
         }
 
-        public void requestExitAndWait() {
-            getLooper().quit();
-            try {
-                this.join();
-            } catch (InterruptedException e) {
-            }
+        public int getRenderMode() {
+            mGLHandler.runWithScissors(mGetRenderModeRunnable, 0);
+            return mGetRenderModeRunnable.renderMode;
         }
     } // class GLThread
 
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 c2dc159..d98f08e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -105,7 +105,7 @@
     public static final boolean DEBUG = BaseStatusBar.DEBUG;
     public static final boolean SPEW = DEBUG;
     public static final boolean DUMPTRUCK = true; // extra dumpsys info
-    public static final boolean DEBUG_GESTURES = true;
+    public static final boolean DEBUG_GESTURES = false;
 
     public static final boolean DEBUG_CLINGS = false;
 
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/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
index 9146ccd..2c25236 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
@@ -30,6 +30,7 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.ServiceManager;
+import android.os.SystemProperties;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -54,7 +55,10 @@
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
-        mDisconnectedReceiver = new UsbDisconnectedReceiver(this);
+        if (SystemProperties.getInt("service.adb.tcp.port", 0) == 0) {
+            mDisconnectedReceiver = new UsbDisconnectedReceiver(this);
+        }
+
         Intent intent = getIntent();
         String fingerprints = intent.getStringExtra("fingerprints");
         mKey = intent.getStringExtra("key");
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 273ac31..7f3fc43 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -251,8 +251,9 @@
     int mLidOpenRotation;
     int mCarDockRotation;
     int mDeskDockRotation;
-    int mHdmiRotation;
-    boolean mHdmiRotationLock;
+    int mUndockedHdmiRotation;
+    int mDemoHdmiRotation;
+    boolean mDemoHdmiRotationLock;
 
     int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
     int mUserRotation = Surface.ROTATION_0;
@@ -854,6 +855,8 @@
                 com.android.internal.R.integer.config_carDockRotation);
         mDeskDockRotation = readRotation(
                 com.android.internal.R.integer.config_deskDockRotation);
+        mUndockedHdmiRotation = readRotation(
+                com.android.internal.R.integer.config_undockedHdmiRotation);
         mCarDockEnablesAccelerometer = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_carDockEnablesAccelerometer);
         mDeskDockEnablesAccelerometer = mContext.getResources().getBoolean(
@@ -1024,11 +1027,11 @@
         // For demo purposes, allow the rotation of the HDMI display to be controlled.
         // By default, HDMI locks rotation to landscape.
         if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) {
-            mHdmiRotation = mPortraitRotation;
+            mDemoHdmiRotation = mPortraitRotation;
         } else {
-            mHdmiRotation = mLandscapeRotation;
+            mDemoHdmiRotation = mLandscapeRotation;
         }
-        mHdmiRotationLock = SystemProperties.getBoolean("persist.demo.hdmirotationlock", false);
+        mDemoHdmiRotationLock = SystemProperties.getBoolean("persist.demo.hdmirotationlock", false);
     }
 
     @Override
@@ -3204,7 +3207,8 @@
                     mDismissKeyguard = mWinDismissingKeyguard == win ?
                             DISMISS_KEYGUARD_CONTINUE : DISMISS_KEYGUARD_START;
                     mWinDismissingKeyguard = win;
-                    mForceStatusBarFromKeyguard = false;
+                    mForceStatusBarFromKeyguard =
+                            mShowingLockscreen && mKeyguardMediator.isSecure();
                 }
                 if ((attrs.flags & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
                     mAllowLockscreenWhenOn = true;
@@ -4199,10 +4203,17 @@
                 // enable 180 degree rotation while docked.
                 preferredRotation = mDeskDockEnablesAccelerometer
                         ? sensorRotation : mDeskDockRotation;
-            } else if (mHdmiPlugged && mHdmiRotationLock) {
-                // Ignore sensor when plugged into HDMI.
+            } else if (mHdmiPlugged && mDemoHdmiRotationLock) {
+                // Ignore sensor when plugged into HDMI when demo HDMI rotation lock enabled.
                 // Note that the dock orientation overrides the HDMI orientation.
-                preferredRotation = mHdmiRotation;
+                preferredRotation = mDemoHdmiRotation;
+            } else if (mHdmiPlugged && mDockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED
+                    && mUndockedHdmiRotation >= 0) {
+                // Ignore sensor when plugged into HDMI and an undocked orientation has
+                // been specified in the configuration (only for legacy devices without
+                // full multi-display support).
+                // Note that the dock orientation overrides the HDMI orientation.
+                preferredRotation = mUndockedHdmiRotation;
             } else if (orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
                 // Application just wants to remain locked in the last rotation.
                 preferredRotation = lastRotation;
@@ -4966,7 +4977,8 @@
                 pw.print(" mSeascapeRotation="); pw.println(mSeascapeRotation);
         pw.print(prefix); pw.print("mPortraitRotation="); pw.print(mPortraitRotation);
                 pw.print(" mUpsideDownRotation="); pw.println(mUpsideDownRotation);
-        pw.print(prefix); pw.print("mHdmiRotation="); pw.print(mHdmiRotation);
-                pw.print(" mHdmiRotationLock="); pw.println(mHdmiRotationLock);
+        pw.print(prefix); pw.print("mDemoHdmiRotation="); pw.print(mDemoHdmiRotation);
+                pw.print(" mDemoHdmiRotationLock="); pw.println(mDemoHdmiRotationLock);
+        pw.print(prefix); pw.print("mUndockedHdmiRotation="); pw.println(mUndockedHdmiRotation);
     }
 }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java
index 965e378..7315aad 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java
@@ -151,7 +151,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
@@ -269,6 +271,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/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java
index 77359ff..9b58803 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java
@@ -23,12 +23,16 @@
 import android.content.Context;
 import android.os.BatteryManager;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.util.Slog;
 import android.view.View;
 import android.widget.TextView;
 
@@ -37,6 +41,8 @@
 import java.lang.ref.WeakReference;
 
 import com.android.internal.R;
+import com.android.internal.widget.ILockSettings;
+import com.android.internal.widget.LockPatternUtils;
 
 /***
  * Manages a number of views inside of the given layout. See below for a list of widgets.
@@ -57,6 +63,8 @@
     static final int SECURITY_MESSAGE_DURATION = 5000;
     protected static final int FADE_DURATION = 750;
 
+    private static final String TAG = "KeyguardMessageArea";
+
     // are we showing battery information?
     boolean mShowingBatteryInfo = false;
 
@@ -82,6 +90,9 @@
 
     CharSequence mMessage;
     boolean mShowingMessage;
+    private CharSequence mSeparator;
+    private LockPatternUtils mLockPatternUtils;
+
     Runnable mClearMessageRunnable = new Runnable() {
         @Override
         public void run() {
@@ -156,8 +167,6 @@
         }
     };
 
-    private CharSequence mSeparator;
-
     public KeyguardMessageArea(Context context) {
         this(context, null);
     }
@@ -165,6 +174,8 @@
     public KeyguardMessageArea(Context context, AttributeSet attrs) {
         super(context, attrs);
 
+        mLockPatternUtils = new LockPatternUtils(context);
+
         // This is required to ensure marquee works
         setSelected(true);
 
@@ -228,11 +239,12 @@
 
     String getOwnerInfo() {
         ContentResolver res = getContext().getContentResolver();
-        final boolean ownerInfoEnabled = Settings.Secure.getIntForUser(res,
-                Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
-        return ownerInfoEnabled && !mShowingMessage ?
-                Settings.Secure.getStringForUser(res, Settings.Secure.LOCK_SCREEN_OWNER_INFO,
-                        UserHandle.USER_CURRENT) : null;
+        String info = null;
+        final boolean ownerInfoEnabled = mLockPatternUtils.isOwnerInfoEnabled();
+        if (ownerInfoEnabled && !mShowingMessage) {
+            info = mLockPatternUtils.getOwnerInfo(mLockPatternUtils.getCurrentUser());
+        }
+        return info;
     }
 
     private CharSequence getChargeInfo(MutableInt icon) {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java
index ad87a4b..986dc49 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java
@@ -124,6 +124,8 @@
             mCallbacks = Lists.newArrayList();
     private ContentObserver mDeviceProvisionedObserver;
 
+    private boolean mSwitchingUser;
+
     private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
@@ -461,11 +463,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) {
@@ -529,7 +533,6 @@
                 cb.onUserSwitching(userId);
             }
         }
-        setAlternateUnlockEnabled(false);
         try {
             reply.sendResult(null);
         } catch (RemoteException e) {
@@ -733,6 +736,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/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
index c49228e..08a95a6 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
@@ -319,8 +319,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/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index a28c387..f872cc3 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -1595,7 +1595,7 @@
                     ApplicationInfo ai = mIPackageManager.getApplicationInfo(imm.getPackageName(),
                             PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
                             mSettings.getCurrentUserId());
-                    if (ai.enabledSetting
+                    if (ai != null && ai.enabledSetting
                             == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
                         mIPackageManager.setApplicationEnabledSetting(imm.getPackageName(),
                                 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
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/LockSettingsService.java b/services/java/com/android/server/LockSettingsService.java
index e20a21f..41cc4d7 100644
--- a/services/java/com/android/server/LockSettingsService.java
+++ b/services/java/com/android/server/LockSettingsService.java
@@ -19,6 +19,11 @@
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+
+import static android.content.Context.USER_SERVICE;
+import static android.Manifest.permission.READ_PROFILE;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
@@ -27,8 +32,10 @@
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.Settings;
 import android.provider.Settings.Secure;
+import android.provider.Settings.SettingNotFoundException;
 import android.text.TextUtils;
 import android.util.Slog;
 
@@ -40,6 +47,7 @@
 import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.util.Arrays;
+import java.util.List;
 
 /**
  * Keeps the lock pattern/password data and related settings for each user.
@@ -79,23 +87,52 @@
 
     private void migrateOldData() {
         try {
-            if (getString("migrated", null, 0) != null) {
-                // Already migrated
-                return;
+            // These Settings moved before multi-user was enabled, so we only have to do it for the
+            // root user.
+            if (getString("migrated", null, 0) == null) {
+                final ContentResolver cr = mContext.getContentResolver();
+                for (String validSetting : VALID_SETTINGS) {
+                    String value = Settings.Secure.getString(cr, validSetting);
+                    if (value != null) {
+                        setString(validSetting, value, 0);
+                    }
+                }
+                // No need to move the password / pattern files. They're already in the right place.
+                setString("migrated", "true", 0);
+                Slog.i(TAG, "Migrated lock settings to new location");
             }
 
-            final ContentResolver cr = mContext.getContentResolver();
-            for (String validSetting : VALID_SETTINGS) {
-                String value = Settings.Secure.getString(cr, validSetting);
-                if (value != null) {
-                    setString(validSetting, value, 0);
+            // These Settings changed after multi-user was enabled, hence need to be moved per user.
+            if (getString("migrated_user_specific", null, 0) == null) {
+                final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
+                final ContentResolver cr = mContext.getContentResolver();
+                List<UserInfo> users = um.getUsers();
+                for (int user = 0; user < users.size(); user++) {
+                    int userId = users.get(user).getUserHandle().getIdentifier();
+                    for (String perUserSetting : MIGRATE_SETTINGS_PER_USER) {
+                        // Handle Strings
+                        String value = Settings.Secure.getStringForUser(cr, perUserSetting, userId);
+                        if (value != null) {
+                            setString(perUserSetting, value, userId);
+                            Settings.Secure.putStringForUser(cr, perUserSetting, "", userId);
+                            continue;
+                        }
+
+                        // Handle integers
+                        try {
+                            int ivalue = Settings.Secure.getIntForUser(cr, perUserSetting, userId);
+                            setLong(perUserSetting, ivalue, userId);
+                            Settings.Secure.putIntForUser(cr, perUserSetting, 0, userId);
+                        } catch (SettingNotFoundException e) {
+                        }
+                    }
                 }
+                // No need to move the password / pattern files. They're already in the right place.
+                setString("migrated_user_specific", "true", 0);
+                Slog.i(TAG, "Migrated per-user lock settings to new location");
             }
-            // No need to move the password / pattern files. They're already in the right place.
-            setString("migrated", "true", 0);
-            Slog.i(TAG, "Migrated lock settings to new location");
         } catch (RemoteException re) {
-            Slog.e(TAG, "Unable to migrate old data");
+            Slog.e(TAG, "Unable to migrate old data", re);
         }
     }
 
@@ -115,12 +152,16 @@
         }
     }
 
-    private static final void checkReadPermission(int userId) {
+    private final void checkReadPermission(String requestedKey, int userId) {
         final int callingUid = Binder.getCallingUid();
-        if (UserHandle.getAppId(callingUid) != android.os.Process.SYSTEM_UID
-                && UserHandle.getUserId(callingUid) != userId) {
-            throw new SecurityException("uid=" + callingUid
-                    + " not authorized to read settings of user " + userId);
+        for (int i = 0; i < READ_PROFILE_PROTECTED_SETTINGS.length; i++) {
+            String key = READ_PROFILE_PROTECTED_SETTINGS[i];
+            if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(READ_PROFILE)
+                    != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException("uid=" + callingUid
+                        + " needs permission " + READ_PROFILE + " to read "
+                        + requestedKey + " for user " + userId);
+            }
         }
     }
 
@@ -147,7 +188,7 @@
 
     @Override
     public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException {
-        //checkReadPermission(userId);
+        checkReadPermission(key, userId);
 
         String value = readFromDb(key, null, userId);
         return TextUtils.isEmpty(value) ?
@@ -156,7 +197,7 @@
 
     @Override
     public long getLong(String key, long defaultValue, int userId) throws RemoteException {
-        //checkReadPermission(userId);
+        checkReadPermission(key, userId);
 
         String value = readFromDb(key, null, userId);
         return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
@@ -164,7 +205,7 @@
 
     @Override
     public String getString(String key, String defaultValue, int userId) throws RemoteException {
-        //checkReadPermission(userId);
+        checkReadPermission(key, userId);
 
         return readFromDb(key, defaultValue, userId);
     }
@@ -404,5 +445,13 @@
         Secure.LOCK_BIOMETRIC_WEAK_FLAGS,
         Secure.LOCK_PATTERN_VISIBLE,
         Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED
-        };
+    };
+
+    private static final String[] MIGRATE_SETTINGS_PER_USER = new String[] {
+        Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
+        Secure.LOCK_SCREEN_OWNER_INFO
+    };
+
+    // These are protected with a read permission
+    private static final String[] READ_PROFILE_PROTECTED_SETTINGS = MIGRATE_SETTINGS_PER_USER;
 }
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index cfb892f..9a93f63 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();
         }
@@ -432,11 +450,16 @@
 
     public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
         checkCallerIsSystem();
-        if (true||DBG) {
-            Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
-        }
+
+        Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
+
         mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
                 enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
+
+        // Now, cancel any outstanding notifications that are part of a just-disabled app
+        if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
+            cancelAllNotificationsInt(pkg, 0, 0, true, UserHandle.getUserId(uid));
+        }
     }
 
 
@@ -815,22 +838,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
@@ -1619,8 +1681,12 @@
                 .getSystemService(Context.AUDIO_SERVICE);
 
                 // sound
+
+                // should we use the default notification sound? (indicated either by DEFAULT_SOUND
+                // or because notification.sound is pointing at Settings.System.NOTIFICATION_SOUND)
                 final boolean useDefaultSound =
-                    (notification.defaults & Notification.DEFAULT_SOUND) != 0;
+                       (notification.defaults & Notification.DEFAULT_SOUND) != 0
+                    || Settings.System.DEFAULT_NOTIFICATION_URI.equals(notification.sound);
 
                 Uri soundUri = null;
                 boolean hasValidSound = false;
@@ -2081,7 +2147,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 +2156,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..2f64908 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -237,6 +237,11 @@
                     }
                     // We will update when the automation service dies.
                     UserState userState = getCurrentUserStateLocked();
+                    // We have to reload the installed services since some services may
+                    // have different attributes, resolve info (does not support equals),
+                    // etc. Remove them then to force reload. Do it even if automation is
+                    // running since when it goes away, we will have to reload as well.
+                    userState.mInstalledServices.clear();
                     if (userState.mUiAutomationService == null) {
                         if (readConfigurationForUserStateLocked(userState)) {
                             onUserStateChangedLocked(userState);
@@ -820,17 +825,21 @@
 
     private boolean notifyKeyEventLocked(KeyEvent event, int policyFlags, boolean isDefault) {
         // TODO: Now we are giving the key events to the last enabled
-        //       service that can handle them which is the last one
-        //       in our list since we write the last enabled as the
-        //       last record in the enabled services setting. Ideally,
-        //       the user should make the call which service handles
-        //       key events. However, only one service should handle
-        //       key events to avoid user frustration when different
-        //       behavior is observed from different combinations of
-        //       enabled accessibility services.
+        //       service that can handle them Ideally, the user should
+        //       make the call which service handles key events. However,
+        //       only one service should handle key events to avoid user
+        //       frustration when different behavior is observed from
+        //       different combinations of enabled accessibility services.
         UserState state = getCurrentUserStateLocked();
         for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
             Service service = state.mBoundServices.get(i);
+            // Key events are handled only by services that declared
+            // this capability and requested to filter key events.
+            if (!service.mRequestFilterKeyEvents ||
+                    (service.mAccessibilityServiceInfo.getCapabilities() & AccessibilityServiceInfo
+                            .CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS) == 0) {
+                continue;
+            }
             if (service.mIsDefault == isDefault) {
                 service.notifyKeyEvent(event, policyFlags);
                 return true;
@@ -970,7 +979,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 +996,7 @@
     private void removeServiceLocked(Service service, UserState userState) {
         userState.mBoundServices.remove(service);
         userState.mComponentNameToServiceMap.remove(service.mComponentName);
-        service.unlinkToOwnDeath();
+        service.unlinkToOwnDeathLocked();
     }
 
     /**
@@ -1160,7 +1169,9 @@
         boolean setInputFilter = false;
         AccessibilityInputFilter inputFilter = null;
         synchronized (mLock) {
-            if (userState.mIsAccessibilityEnabled) {
+            // Accessibility enabled means at least one service is enabled.
+            if (userState.mIsAccessibilityEnabled
+                    || userState.mIsDisplayMagnificationEnabled) {
                 if (!mHasInputFilter) {
                     mHasInputFilter = true;
                     if (mInputFilter == null) {
@@ -1174,7 +1185,8 @@
                 if (userState.mIsDisplayMagnificationEnabled) {
                     flags |= AccessibilityInputFilter.FLAG_FEATURE_SCREEN_MAGNIFIER;
                 }
-                if (userState.mIsTouchExplorationEnabled) {
+                // Touch exploration without accessibility makes no sense.
+                if (userState.mIsAccessibilityEnabled && userState.mIsTouchExplorationEnabled) {
                     flags |= AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION;
                 }
                 mInputFilter.setEnabledFeatures(flags);
@@ -1366,11 +1378,11 @@
                 return true;
             }
         } else {
-            // Starting in JB-MR2 we request a permission to allow a service to enable
-            // touch exploration and do not care if the service is in the white list.
-            if (mContext.getPackageManager().checkPermission(
-                    android.Manifest.permission.CAN_REQUEST_TOUCH_EXPLORATION_MODE,
-                    service.mComponentName.getPackageName()) == PackageManager.PERMISSION_GRANTED) {
+            // Starting in JB-MR2 we request an accessibility service to declare
+            // certain capabilities in its meta-data to allow it to enable the
+            // corresponding features.
+            if (service.mIsAutomation || (service.mAccessibilityServiceInfo.getCapabilities()
+                    & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION) != 0) {
                 userState.mIsTouchExplorationEnabled = true;
                 Settings.Secure.putIntForUser(mContext.getContentResolver(),
                         Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1, service.mUserId);
@@ -1399,9 +1411,8 @@
         if (userState.mIsEnhancedWebAccessibilityEnabled) {
             return false;
         }
-        if (service.mIsAutomation || mContext.getPackageManager().checkPermission(
-                android.Manifest.permission.CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY,
-                service.mComponentName.getPackageName()) == PackageManager.PERMISSION_GRANTED) {
+        if (service.mIsAutomation || (service.mAccessibilityServiceInfo.getCapabilities()
+               & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY) != 0) {
             userState.mIsEnhancedWebAccessibilityEnabled = true;
             Settings.Secure.putIntForUser(mContext.getContentResolver(),
                     Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 1, userState.mUserId);
@@ -1636,6 +1647,8 @@
 
         boolean mRequestEnhancedWebAccessibility;
 
+        boolean mRequestFilterKeyEvents;
+
         int mFetchFlags;
 
         long mNotificationTimeout;
@@ -1681,7 +1694,8 @@
             mAccessibilityServiceInfo = accessibilityServiceInfo;
             mIsAutomation = (sFakeAccessibilityServiceComponentName.equals(componentName));
             if (!mIsAutomation) {
-                mCanRetrieveScreenContent = accessibilityServiceInfo.getCanRetrieveWindowContent();
+                mCanRetrieveScreenContent = (accessibilityServiceInfo.getCapabilities()
+                        & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION) != 0;
                 mIntent = new Intent().setComponent(mComponentName);
                 mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
                         com.android.internal.R.string.accessibility_binding_label);
@@ -1720,9 +1734,11 @@
 
             if (mResolveInfo != null) {
                 mRequestTouchExplorationMode = (info.flags
-                            & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
+                        & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
                 mRequestEnhancedWebAccessibility = (info.flags
-                           & AccessibilityServiceInfo.FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY) != 0;
+                        & AccessibilityServiceInfo.FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY) != 0;
+                mRequestFilterKeyEvents = (info.flags
+                        & AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS)  != 0;
             }
         }
 
@@ -1765,7 +1781,7 @@
                 userState.destroyUiAutomationService();
             }
             removeServiceLocked(this, userState);
-            dispose();
+            resetLocked();
             return true;
         }
 
@@ -1817,11 +1833,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 +2166,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 +2186,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 +2528,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 bc1df85..1d17da9 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -4967,6 +4967,10 @@
             return ActivityManagerService.this.checkComponentPermission(permission, pid, uid,
                     owningUid, exported);
         }
+
+        public Object getAMSLock() {
+            return ActivityManagerService.this;
+        }
     }
 
     /**
diff --git a/services/java/com/android/server/am/NativeCrashListener.java b/services/java/com/android/server/am/NativeCrashListener.java
index 0688c50..de439d7 100644
--- a/services/java/com/android/server/am/NativeCrashListener.java
+++ b/services/java/com/android/server/am/NativeCrashListener.java
@@ -43,13 +43,14 @@
 class NativeCrashListener extends Thread {
     static final String TAG = "NativeCrashListener";
     static final boolean DEBUG = false;
+    static final boolean MORE_DEBUG = DEBUG && false;
 
     // Must match the path defined in debuggerd.c.
     static final String DEBUGGERD_SOCKET_PATH = "/data/system/ndebugsocket";
 
     // Use a short timeout on socket operations and abandon the connection
     // on hard errors
-    static final long SOCKET_TIMEOUT_MILLIS = 1000;  // 1 second
+    static final long SOCKET_TIMEOUT_MILLIS = 2000;  // 2 seconds
 
     final ActivityManagerService mAm;
 
@@ -124,9 +125,9 @@
                 InetSocketAddress peer = new InetSocketAddress();
                 FileDescriptor peerFd = null;
                 try {
-                    if (DEBUG) Slog.v(TAG, "Waiting for debuggerd connection");
+                    if (MORE_DEBUG) Slog.v(TAG, "Waiting for debuggerd connection");
                     peerFd = Libcore.os.accept(serverFd, peer);
-                    if (DEBUG) Slog.v(TAG, "Got debuggerd socket " + peerFd);
+                    if (MORE_DEBUG) Slog.v(TAG, "Got debuggerd socket " + peerFd);
                     if (peerFd != null) {
                         // Only the superuser is allowed to talk to us over this socket
                         StructUcred credentials =
@@ -145,7 +146,12 @@
                     if (peerFd != null) {
                         try {
                             Libcore.os.write(peerFd, ackSignal, 0, 1);
-                        } catch (Exception e) { /* we don't care about failures here */ }
+                        } catch (Exception e) {
+                            /* we don't care about failures here */
+                            if (MORE_DEBUG) {
+                                Slog.d(TAG, "Exception writing ack: " + e.getMessage());
+                            }
+                        }
                     }
                 }
             }
@@ -183,7 +189,7 @@
 
     // Read the crash report from the debuggerd connection
     void consumeNativeCrashData(FileDescriptor fd) {
-        if (DEBUG) Slog.i(TAG, "debuggerd connected");
+        if (MORE_DEBUG) Slog.i(TAG, "debuggerd connected");
         final byte[] buf = new byte[4096];
         final ByteArrayOutputStream os = new ByteArrayOutputStream(4096);
 
@@ -218,7 +224,7 @@
                         // get some data
                         bytes = Libcore.os.read(fd, buf, 0, buf.length);
                         if (bytes > 0) {
-                            if (DEBUG) {
+                            if (MORE_DEBUG) {
                                 String s = new String(buf, 0, bytes, "UTF-8");
                                 Slog.v(TAG, "READ=" + bytes + "> " + s);
                             }
diff --git a/services/java/com/android/server/display/WifiDisplayController.java b/services/java/com/android/server/display/WifiDisplayController.java
index a83675e..8c8b360 100644
--- a/services/java/com/android/server/display/WifiDisplayController.java
+++ b/services/java/com/android/server/display/WifiDisplayController.java
@@ -481,6 +481,7 @@
             mRemoteDisplayConnected = false;
             mHandler.removeCallbacks(mRtspTimeout);
 
+            mWifiP2pManager.setMiracastMode(WifiP2pManager.MIRACAST_DISABLED);
             setRemoteSubmixOn(false);
             unadvertiseDisplay();
 
@@ -626,6 +627,7 @@
             }
 
             setRemoteSubmixOn(true);
+            mWifiP2pManager.setMiracastMode(WifiP2pManager.MIRACAST_SOURCE);
 
             final WifiP2pDevice oldDevice = mConnectedDevice;
             final int port = getPortNumber(mConnectedDevice);
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/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index df90a56..11c6dab 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -88,8 +88,13 @@
     private static final String TAG_ENTRY = "entry";
     private static final String TAG_VALUE = "value";
     private static final String ATTR_KEY = "key";
+    private static final String ATTR_VALUE_TYPE = "type";
     private static final String ATTR_MULTIPLE = "m";
 
+    private static final String ATTR_TYPE_STRING_ARRAY = "sa";
+    private static final String ATTR_TYPE_STRING = "s";
+    private static final String ATTR_TYPE_BOOLEAN = "b";
+
     private static final String USER_INFO_DIR = "system" + File.separator + "users";
     private static final String USER_LIST_FILENAME = "userlist.xml";
     private static final String USER_PHOTO_FILENAME = "photo.png";
@@ -965,7 +970,12 @@
     }
 
     @Override
-    public List<RestrictionEntry> getApplicationRestrictions(String packageName, int userId) {
+    public Bundle getApplicationRestrictions(String packageName) {
+        return getApplicationRestrictionsForUser(packageName, UserHandle.getCallingUserId());
+    }
+
+    @Override
+    public Bundle getApplicationRestrictionsForUser(String packageName, int userId) {
         if (UserHandle.getCallingUserId() != userId
                 || !UserHandle.isSameApp(Binder.getCallingUid(), getUidForPackage(packageName))) {
             checkManageUsersPermission("Only system can get restrictions for other users/apps");
@@ -977,7 +987,7 @@
     }
 
     @Override
-    public void setApplicationRestrictions(String packageName, List<RestrictionEntry> entries,
+    public void setApplicationRestrictions(String packageName, Bundle restrictions,
             int userId) {
         if (UserHandle.getCallingUserId() != userId
                 || !UserHandle.isSameApp(Binder.getCallingUid(), getUidForPackage(packageName))) {
@@ -985,7 +995,7 @@
         }
         synchronized (mPackagesLock) {
             // Write the restrictions to XML
-            writeApplicationRestrictionsLocked(packageName, entries, userId);
+            writeApplicationRestrictionsLocked(packageName, restrictions, userId);
         }
     }
 
@@ -1001,9 +1011,9 @@
         }
     }
 
-    private List<RestrictionEntry> readApplicationRestrictionsLocked(String packageName,
+    private Bundle readApplicationRestrictionsLocked(String packageName,
             int userId) {
-        final ArrayList<RestrictionEntry> entries = new ArrayList<RestrictionEntry>();
+        final Bundle restrictions = new Bundle();
         final ArrayList<String> values = new ArrayList<String>();
 
         FileInputStream fis = null;
@@ -1023,12 +1033,13 @@
             if (type != XmlPullParser.START_TAG) {
                 Slog.e(LOG_TAG, "Unable to read restrictions file "
                         + restrictionsFile.getBaseFile());
-                return entries;
+                return restrictions;
             }
 
             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
                 if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_ENTRY)) {
                     String key = parser.getAttributeValue(null, ATTR_KEY);
+                    String valType = parser.getAttributeValue(null, ATTR_VALUE_TYPE);
                     String multiple = parser.getAttributeValue(null, ATTR_MULTIPLE);
                     if (multiple != null) {
                         int count = Integer.parseInt(multiple);
@@ -1041,14 +1052,13 @@
                         }
                         String [] valueStrings = new String[values.size()];
                         values.toArray(valueStrings);
-                        Slog.d(LOG_TAG, "Got RestrictionEntry " + key + "," + valueStrings);
-                        RestrictionEntry entry = new RestrictionEntry(key, valueStrings);
-                        entries.add(entry);
+                        restrictions.putStringArray(key, valueStrings);
+                    } else if (ATTR_TYPE_BOOLEAN.equals(valType)) {
+                        restrictions.putBoolean(key, Boolean.parseBoolean(
+                                parser.nextText().trim()));
                     } else {
                         String value = parser.nextText().trim();
-                        Slog.d(LOG_TAG, "Got RestrictionEntry " + key + "," + value);
-                        RestrictionEntry entry = new RestrictionEntry(key, value);
-                        entries.add(entry);
+                        restrictions.putString(key, value);
                     }
                 }
             }
@@ -1063,11 +1073,11 @@
                 }
             }
         }
-        return entries;
+        return restrictions;
     }
 
     private void writeApplicationRestrictionsLocked(String packageName,
-            List<RestrictionEntry> entries, int userId) {
+            Bundle restrictions, int userId) {
         FileOutputStream fos = null;
         AtomicFile restrictionsFile = new AtomicFile(
                 new File(Environment.getUserSystemDirectory(userId),
@@ -1084,18 +1094,24 @@
 
             serializer.startTag(null, TAG_RESTRICTIONS);
 
-            for (RestrictionEntry entry : entries) {
+            for (String key : restrictions.keySet()) {
+                Object value = restrictions.get(key);
                 serializer.startTag(null, TAG_ENTRY);
-                serializer.attribute(null, ATTR_KEY, entry.getKey());
-                if (entry.getSelectedString() != null || entry.getAllSelectedStrings() == null) {
-                    String value = entry.getSelectedString();
-                    serializer.text(value != null ? value : "");
+                serializer.attribute(null, ATTR_KEY, key);
+
+                if (value instanceof Boolean) {
+                    serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_BOOLEAN);
+                    serializer.text(value.toString());
+                } else if (value == null || value instanceof String) {
+                    serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_STRING);
+                    serializer.text(value != null ? (String) value : "");
                 } else {
-                    String[] values = entry.getAllSelectedStrings();
+                    serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_STRING_ARRAY);
+                    String[] values = (String[]) value;
                     serializer.attribute(null, ATTR_MULTIPLE, Integer.toString(values.length));
-                    for (String value : values) {
+                    for (String choice : values) {
                         serializer.startTag(null, TAG_VALUE);
-                        serializer.text(value != null ? value : "");
+                        serializer.text(choice != null ? choice : "");
                         serializer.endTag(null, TAG_VALUE);
                     }
                 }
diff --git a/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java b/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
index c94f7c1..9601e9a 100644
--- a/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
+++ b/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
@@ -56,9 +56,9 @@
 
     private static final String UPDATE_CERTIFICATE_KEY = "config_update_certificate";
 
-    private final File updateDir;
-    private final File updateContent;
-    private final File updateVersion;
+    protected final File updateDir;
+    protected final File updateContent;
+    protected final File updateVersion;
 
     public ConfigUpdateInstallReceiver(String updateDir, String updateContentPath,
                                        String updateMetadataPath, String updateVersionPath) {
@@ -222,7 +222,7 @@
         return signer.verify(Base64.decode(signature.getBytes(), Base64.DEFAULT));
     }
 
-    private void writeUpdate(File dir, File file, byte[] content) throws IOException {
+    protected void writeUpdate(File dir, File file, byte[] content) throws IOException {
         FileOutputStream out = null;
         File tmp = null;
         try {
diff --git a/services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java b/services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
index 748849e..e8337f6 100644
--- a/services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
+++ b/services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
@@ -18,28 +18,127 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.os.FileUtils;
 import android.os.SELinux;
+import android.os.SystemProperties;
 import android.provider.Settings;
 import android.util.Base64;
 import android.util.Slog;
 
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
 
+import libcore.io.ErrnoException;
+import libcore.io.IoUtils;
+import libcore.io.Libcore;
+
 public class SELinuxPolicyInstallReceiver extends ConfigUpdateInstallReceiver {
 
+    private static final String TAG = "SELinuxPolicyInstallReceiver";
+
+    private static final String sepolicyPath = "sepolicy";
+    private static final String fileContextsPath = "file_contexts";
+    private static final String propertyContextsPath = "property_contexts";
+    private static final String seappContextsPath = "seapp_contexts";
+
     public SELinuxPolicyInstallReceiver() {
-        super("/data/security/", "sepolicy", "metadata/", "version");
+        super("/data/security/bundle", "sepolicy_bundle", "metadata/", "version");
     }
 
-    @Override
-    protected void install(byte[] encodedContent, int version) throws IOException {
-        super.install(Base64.decode(encodedContent, Base64.DEFAULT), version);
+    private void backupContexts(File contexts) {
+        new File(contexts, seappContextsPath).renameTo(
+                new File(contexts, seappContextsPath + "_backup"));
+
+        new File(contexts, propertyContextsPath).renameTo(
+                new File(contexts, propertyContextsPath + "_backup"));
+
+        new File(contexts, fileContextsPath).renameTo(
+                new File(contexts, fileContextsPath + "_backup"));
+
+        new File(contexts, sepolicyPath).renameTo(
+                new File(contexts, sepolicyPath + "_backup"));
+    }
+
+    private void copyUpdate(File contexts) {
+        new File(updateDir, seappContextsPath).renameTo(new File(contexts, seappContextsPath));
+        new File(updateDir, propertyContextsPath).renameTo(new File(contexts, propertyContextsPath));
+        new File(updateDir, fileContextsPath).renameTo(new File(contexts, fileContextsPath));
+        new File(updateDir, sepolicyPath).renameTo(new File(contexts, sepolicyPath));
+    }
+
+    private int readInt(BufferedInputStream reader) throws IOException {
+        int value = 0;
+        for (int i=0; i < 4; i++) {
+            value = (value << 8) | reader.read();
+        }
+        return value;
+    }
+
+    private int[] readChunkLengths(BufferedInputStream bundle) throws IOException {
+        int[] chunks = new int[4];
+        chunks[0] = readInt(bundle);
+        chunks[1] = readInt(bundle);
+        chunks[2] = readInt(bundle);
+        chunks[3] = readInt(bundle);
+        return chunks;
+    }
+
+    private void installFile(File destination, BufferedInputStream stream, int length)
+            throws IOException {
+        byte[] chunk = new byte[length];
+        stream.read(chunk, 0, length);
+        writeUpdate(updateDir, destination, Base64.decode(chunk, Base64.DEFAULT));
+    }
+
+    private void unpackBundle() throws IOException {
+        BufferedInputStream stream = new BufferedInputStream(new FileInputStream(updateContent));
+        int[] chunkLengths = readChunkLengths(stream);
+        installFile(new File(updateDir, seappContextsPath), stream, chunkLengths[0]);
+        installFile(new File(updateDir, propertyContextsPath), stream, chunkLengths[1]);
+        installFile(new File(updateDir, fileContextsPath), stream, chunkLengths[2]);
+        installFile(new File(updateDir, sepolicyPath), stream, chunkLengths[3]);
+    }
+
+    private void applyUpdate() throws IOException, ErrnoException {
+        Slog.i(TAG, "Applying SELinux policy");
+        File contexts = new File(updateDir.getParentFile(), "contexts");
+        File current = new File(updateDir.getParentFile(), "current");
+        File update = new File(updateDir.getParentFile(), "update");
+        File tmp = new File(updateDir.getParentFile(), "tmp");
+        if (current.exists()) {
+            Libcore.os.symlink(updateDir.getPath(), update.getPath());
+            Libcore.os.rename(update.getPath(), current.getPath());
+        } else {
+            Libcore.os.symlink(updateDir.getPath(), current.getPath());
+        }
+        contexts.mkdirs();
+        backupContexts(contexts);
+        copyUpdate(contexts);
+        Libcore.os.symlink(contexts.getPath(), tmp.getPath());
+        Libcore.os.rename(tmp.getPath(), current.getPath());
+        SystemProperties.set("selinux.reload_policy", "1");
+    }
+
+    private void setEnforcingMode(Context context) {
+        boolean mode = Settings.Global.getInt(context.getContentResolver(),
+            Settings.Global.SELINUX_STATUS, 0) == 1;
+        SELinux.setSELinuxEnforce(mode);
     }
 
     @Override
     protected void postInstall(Context context, Intent intent) {
-           boolean mode = Settings.Global.getInt(context.getContentResolver(),
-                                                Settings.Global.SELINUX_STATUS, 0) == 1;
-           SELinux.setSELinuxEnforce(mode);
+        try {
+            unpackBundle();
+            applyUpdate();
+            setEnforcingMode(context);
+        } catch (IllegalArgumentException e) {
+            Slog.e(TAG, "SELinux policy update malformed: ", e);
+        } catch (IOException e) {
+            Slog.e(TAG, "Could not update selinux policy: ", e);
+        } catch (ErrnoException e) {
+            Slog.e(TAG, "Could not update selinux policy: ", e);
+        }
     }
 }
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 1d1fda5..bc442ce 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -5490,6 +5490,7 @@
         ScreenRotationAnimation.createRotationMatrix(rot, dw, dh, matrix);
         matrix.postTranslate(-FloatMath.ceil(frame.left*scale), -FloatMath.ceil(frame.top*scale));
         Canvas canvas = new Canvas(bm);
+        canvas.drawColor(0xFF000000);
         canvas.drawBitmap(rawss, matrix, null);
         canvas.setBitmap(null);
 
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index ca060f4..788d514 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;
@@ -923,6 +924,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/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java
index 31e01c0..dbd48d9 100644
--- a/telephony/java/android/telephony/CellIdentityCdma.java
+++ b/telephony/java/android/telephony/CellIdentityCdma.java
@@ -93,21 +93,21 @@
     }
 
     /**
-     * @return Network Id 0..65535
+     * @return Network Id 0..65535, Integer.MAX_VALUE if unknown
      */
     public int getNetworkId() {
         return mNetworkId;
     }
 
     /**
-     * @return System Id 0..32767
+     * @return System Id 0..32767, Integer.MAX_VALUE if unknown
      */
     public int getSystemId() {
         return mSystemId;
     }
 
     /**
-     * @return Base Station Id 0..65535
+     * @return Base Station Id 0..65535, Integer.MAX_VALUE if unknown
      */
     public int getBasestationId() {
         return mBasestationId;
@@ -118,7 +118,7 @@
      * specified in 3GPP2 C.S0005-A v6.0. It is represented in units
      * of 0.25 seconds and ranges from -2592000 to 2592000, both
      * values inclusive (corresponding to a range of -180
-     * to +180 degrees).
+     * to +180 degrees). Integer.MAX_VALUE if unknown.
      */
     public int getLongitude() {
         return mLongitude;
@@ -129,7 +129,7 @@
      * specified in 3GPP2 C.S0005-A v6.0. It is represented in units
      * of 0.25 seconds and ranges from -1296000 to 1296000, both
      * values inclusive (corresponding to a range of -90
-     * to +90 degrees).
+     * to +90 degrees). Integer.MAX_VALUE if unknown.
      */
     public int getLatitude() {
         return mLatitude;
@@ -162,7 +162,7 @@
 
     @Override
     public String toString() {
-        StringBuilder sb = new StringBuilder("CellIdentitiyCdma:{");
+        StringBuilder sb = new StringBuilder("CellIdentityCdma:{");
         sb.append(" mNetworkId="); sb.append(mNetworkId);
         sb.append(" mSystemId="); sb.append(mSystemId);
         sb.append(" mBasestationId="); sb.append(mBasestationId);
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index 98113e7..6f8cc91 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -21,7 +21,7 @@
 import android.telephony.Rlog;
 
 /**
- * CellIdentity to represent a unique GSM or UMTS cell
+ * CellIdentity to represent a unique GSM cell
  */
 public final class CellIdentityGsm implements Parcelable {
 
@@ -35,10 +35,7 @@
     // 16-bit Location Area Code, 0..65535
     private final int mLac;
     // 16-bit GSM Cell Identity described in TS 27.007, 0..65535
-    // 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455
     private final int mCid;
-    // 9-bit UMTS Primary Scrambling Code described in TS 25.331, 0..511
-    private final int mPsc;
 
     /**
      * @hide
@@ -48,7 +45,6 @@
         mMnc = Integer.MAX_VALUE;
         mLac = Integer.MAX_VALUE;
         mCid = Integer.MAX_VALUE;
-        mPsc = Integer.MAX_VALUE;
     }
     /**
      * public constructor
@@ -56,16 +52,14 @@
      * @param mnc 2 or 3-digit Mobile Network Code, 0..999
      * @param lac 16-bit Location Area Code, 0..65535
      * @param cid 16-bit GSM Cell Identity or 28-bit UMTS Cell Identity
-     * @param psc 9-bit UMTS Primary Scrambling Code
      *
      * @hide
      */
-    public CellIdentityGsm (int mcc, int mnc, int lac, int cid, int psc) {
+    public CellIdentityGsm (int mcc, int mnc, int lac, int cid) {
         mMcc = mcc;
         mMnc = mnc;
         mLac = lac;
         mCid = cid;
-        mPsc = psc;
     }
 
     private CellIdentityGsm(CellIdentityGsm cid) {
@@ -73,7 +67,6 @@
         mMnc = cid.mMnc;
         mLac = cid.mLac;
         mCid = cid.mCid;
-        mPsc = cid.mPsc;
     }
 
     CellIdentityGsm copy() {
@@ -81,21 +74,21 @@
     }
 
     /**
-     * @return 3-digit Mobile Country Code, 0..999
+     * @return 3-digit Mobile Country Code, 0..999, Integer.MAX_VALUE if unknown
      */
     public int getMcc() {
         return mMcc;
     }
 
     /**
-     * @return 2 or 3-digit Mobile Network Code, 0..999
+     * @return 2 or 3-digit Mobile Network Code, 0..999, Integer.MAX_VALUE if unknown
      */
     public int getMnc() {
         return mMnc;
     }
 
     /**
-     * @return 16-bit Location Area Code, 0..65535
+     * @return 16-bit Location Area Code, 0..65535, Integer.MAX_VALUE if unknown
      */
     public int getLac() {
         return mLac;
@@ -104,27 +97,24 @@
     /**
      * @return CID
      * Either 16-bit GSM Cell Identity described
-     * in TS 27.007, 0..65535
-     * or 28-bit UMTS Cell Identity described
-     * in TS 25.331, 0..268435455
+     * in TS 27.007, 0..65535, Integer.MAX_VALUE if unknown
      */
     public int getCid() {
         return mCid;
     }
 
     /**
-     * @return 9-bit UMTS Primary Scrambling Code described in
-     * TS 25.331, 0..511
+     * @return Integer.MAX_VALUE, undefined for GSM
      */
+    @Deprecated
     public int getPsc() {
-        return mPsc;
+        return Integer.MAX_VALUE;
     }
 
     @Override
     public int hashCode() {
         int primeNum = 31;
-        return (mMcc * primeNum) + (mMnc * primeNum) + (mLac * primeNum) + (mCid * primeNum) +
-                (mPsc * primeNum);
+        return (mMcc * primeNum) + (mMnc * primeNum) + (mLac * primeNum) + (mCid * primeNum);
     }
 
     @Override
@@ -135,8 +125,7 @@
                 return mMcc == o.mMcc &&
                         mMnc == o.mMnc &&
                         mLac == o.mLac &&
-                        mCid == o.mCid &&
-                        mPsc == o.mPsc;
+                        mCid == o.mCid;
             } catch (ClassCastException e) {
                 return false;
             }
@@ -147,12 +136,11 @@
 
     @Override
     public String toString() {
-        StringBuilder sb = new StringBuilder("CellIdentitiyGsm:{");
+        StringBuilder sb = new StringBuilder("CellIdentityGsm:{");
         sb.append(" mMcc=").append(mMcc);
         sb.append(" mMnc=").append(mMnc);
         sb.append(" mLac=").append(mLac);
         sb.append(" mCid=").append(mCid);
-        sb.append(" mPsc=").append(mPsc);
         sb.append("}");
 
         return sb.toString();
@@ -172,7 +160,6 @@
         dest.writeInt(mMnc);
         dest.writeInt(mLac);
         dest.writeInt(mCid);
-        dest.writeInt(mPsc);
     }
 
     /** Construct from Parcel, type has already been processed */
@@ -181,7 +168,6 @@
         mMnc = in.readInt();
         mLac = in.readInt();
         mCid = in.readInt();
-        mPsc = in.readInt();
         if (DBG) log("CellIdentityGsm(Parcel): " + toString());
     }
 
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 86924bd..13b39c9 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -81,35 +81,35 @@
     }
 
     /**
-     * @return 3-digit Mobile Country Code, 0..999
+     * @return 3-digit Mobile Country Code, 0..999, Integer.MAX_VALUE if unknown
      */
     public int getMcc() {
         return mMcc;
     }
 
     /**
-     * @return 2 or 3-digit Mobile Network Code, 0..999
+     * @return 2 or 3-digit Mobile Network Code, 0..999, Integer.MAX_VALUE if unknown
      */
     public int getMnc() {
         return mMnc;
     }
 
     /**
-     * @return 28-bit Cell Identity
+     * @return 28-bit Cell Identity, Integer.MAX_VALUE if unknown
      */
     public int getCi() {
         return mCi;
     }
 
     /**
-     * @return Physical Cell Id 0..503
+     * @return Physical Cell Id 0..503, Integer.MAX_VALUE if unknown
      */
     public int getPci() {
         return mPci;
     }
 
     /**
-     * @return 16-bit Tracking Area Code
+     * @return 16-bit Tracking Area Code, Integer.MAX_VALUE if unknown
      */
     public int getTac() {
         return mTac;
@@ -142,7 +142,7 @@
 
     @Override
     public String toString() {
-        StringBuilder sb = new StringBuilder("CellIdentitiyLte:{");
+        StringBuilder sb = new StringBuilder("CellIdentityLte:{");
         sb.append(" mMcc="); sb.append(mMcc);
         sb.append(" mMnc="); sb.append(mMnc);
         sb.append(" mCi="); sb.append(mCi);
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
new file mode 100644
index 0000000..2f8fa42
--- /dev/null
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -0,0 +1,205 @@
+/*
+ * 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.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.Rlog;
+
+/**
+ * CellIdentity to represent a unique UMTS cell
+ */
+public final class CellIdentityWcdma implements Parcelable {
+
+    private static final String LOG_TAG = "CellIdentityWcdma";
+    private static final boolean DBG = false;
+
+    // 3-digit Mobile Country Code, 0..999
+    private final int mMcc;
+    // 2 or 3-digit Mobile Network Code, 0..999
+    private final int mMnc;
+    // 16-bit Location Area Code, 0..65535
+    private final int mLac;
+    // 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455
+    private final int mCid;
+    // 9-bit UMTS Primary Scrambling Code described in TS 25.331, 0..511
+    private final int mPsc;
+
+    /**
+     * @hide
+     */
+    public CellIdentityWcdma() {
+        mMcc = Integer.MAX_VALUE;
+        mMnc = Integer.MAX_VALUE;
+        mLac = Integer.MAX_VALUE;
+        mCid = Integer.MAX_VALUE;
+        mPsc = Integer.MAX_VALUE;
+    }
+    /**
+     * public constructor
+     * @param mcc 3-digit Mobile Country Code, 0..999
+     * @param mnc 2 or 3-digit Mobile Network Code, 0..999
+     * @param lac 16-bit Location Area Code, 0..65535
+     * @param cid 28-bit UMTS Cell Identity
+     * @param psc 9-bit UMTS Primary Scrambling Code
+     *
+     * @hide
+     */
+    public CellIdentityWcdma (int mcc, int mnc, int lac, int cid, int psc) {
+        mMcc = mcc;
+        mMnc = mnc;
+        mLac = lac;
+        mCid = cid;
+        mPsc = psc;
+    }
+
+    private CellIdentityWcdma(CellIdentityWcdma cid) {
+        mMcc = cid.mMcc;
+        mMnc = cid.mMnc;
+        mLac = cid.mLac;
+        mCid = cid.mCid;
+        mPsc = cid.mPsc;
+    }
+
+    CellIdentityWcdma copy() {
+       return new CellIdentityWcdma(this);
+    }
+
+    /**
+     * @return 3-digit Mobile Country Code, 0..999, Integer.MAX_VALUE if unknown
+     */
+    public int getMcc() {
+        return mMcc;
+    }
+
+    /**
+     * @return 2 or 3-digit Mobile Network Code, 0..999, Integer.MAX_VALUE if unknown
+     */
+    public int getMnc() {
+        return mMnc;
+    }
+
+    /**
+     * @return 16-bit Location Area Code, 0..65535, Integer.MAX_VALUE if unknown
+     */
+    public int getLac() {
+        return mLac;
+    }
+
+    /**
+     * @return CID
+     * 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, Integer.MAX_VALUE if unknown
+     */
+    public int getCid() {
+        return mCid;
+    }
+
+    /**
+     * @return 9-bit UMTS Primary Scrambling Code described in TS 25.331, 0..511, Integer.MAX_VALUE
+     * if unknown
+     */
+    public int getPsc() {
+        return mPsc;
+    }
+
+    @Override
+    public int hashCode() {
+        int primeNum = 31;
+        return (mMcc * primeNum) + (mMnc * primeNum) + (mLac * primeNum) + (mCid * primeNum) +
+                (mPsc * primeNum);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (super.equals(other)) {
+            try {
+                CellIdentityWcdma o = (CellIdentityWcdma)other;
+                return mMcc == o.mMcc &&
+                        mMnc == o.mMnc &&
+                        mLac == o.mLac &&
+                        mCid == o.mCid &&
+                        mPsc == o.mPsc;
+            } catch (ClassCastException e) {
+                return false;
+            }
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("CellIdentityWcdma:{");
+        sb.append(" mMcc=").append(mMcc);
+        sb.append(" mMnc=").append(mMnc);
+        sb.append(" mLac=").append(mLac);
+        sb.append(" mCid=").append(mCid);
+        sb.append(" mPsc=").append(mPsc);
+        sb.append("}");
+
+        return sb.toString();
+    }
+
+    /** Implement the Parcelable interface */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        if (DBG) log("writeToParcel(Parcel, int): " + toString());
+        dest.writeInt(mMcc);
+        dest.writeInt(mMnc);
+        dest.writeInt(mLac);
+        dest.writeInt(mCid);
+        dest.writeInt(mPsc);
+    }
+
+    /** Construct from Parcel, type has already been processed */
+    private CellIdentityWcdma(Parcel in) {
+        mMcc = in.readInt();
+        mMnc = in.readInt();
+        mLac = in.readInt();
+        mCid = in.readInt();
+        mPsc = in.readInt();
+        if (DBG) log("CellIdentityWcdma(Parcel): " + toString());
+    }
+
+    /** Implement the Parcelable interface */
+    @SuppressWarnings("hiding")
+    public static final Creator<CellIdentityWcdma> CREATOR =
+            new Creator<CellIdentityWcdma>() {
+        @Override
+        public CellIdentityWcdma createFromParcel(Parcel in) {
+            return new CellIdentityWcdma(in);
+        }
+
+        @Override
+        public CellIdentityWcdma[] newArray(int size) {
+            return new CellIdentityWcdma[size];
+        }
+    };
+
+    /**
+     * log
+     */
+    private static void log(String s) {
+        Rlog.w(LOG_TAG, s);
+    }
+}
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index fe3c68b..bfa0942 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -31,6 +31,8 @@
     protected static final int TYPE_CDMA = 2;
     /** @hide */
     protected static final int TYPE_LTE = 3;
+    /** @hide */
+    protected static final int TYPE_WCDMA = 4;
 
     // Type to distinguish where time stamp gets recorded.
 
@@ -201,6 +203,7 @@
                     case TYPE_GSM: return CellInfoGsm.createFromParcelBody(in);
                     case TYPE_CDMA: return CellInfoCdma.createFromParcelBody(in);
                     case TYPE_LTE: return CellInfoLte.createFromParcelBody(in);
+                    case TYPE_WCDMA: return CellInfoWcdma.createFromParcelBody(in);
                     default: throw new RuntimeException("Bad CellInfo Parcel");
                 }
         }
diff --git a/telephony/java/android/telephony/CellInfoWcdma.java b/telephony/java/android/telephony/CellInfoWcdma.java
new file mode 100644
index 0000000..0615702
--- /dev/null
+++ b/telephony/java/android/telephony/CellInfoWcdma.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.Rlog;
+
+/**
+ * Immutable cell information from a point in time.
+ */
+public final class CellInfoWcdma extends CellInfo implements Parcelable {
+
+    private static final String LOG_TAG = "CellInfoWcdma";
+    private static final boolean DBG = false;
+
+    private CellIdentityWcdma mCellIdentityWcdma;
+    private CellSignalStrengthWcdma mCellSignalStrengthWcdma;
+
+    /** @hide */
+    public CellInfoWcdma() {
+        super();
+        mCellIdentityWcdma = new CellIdentityWcdma();
+        mCellSignalStrengthWcdma = new CellSignalStrengthWcdma();
+    }
+
+    /** @hide */
+    public CellInfoWcdma(CellInfoWcdma ci) {
+        super(ci);
+        this.mCellIdentityWcdma = ci.mCellIdentityWcdma.copy();
+        this.mCellSignalStrengthWcdma = ci.mCellSignalStrengthWcdma.copy();
+    }
+
+    public CellIdentityWcdma getCellIdentity() {
+        return mCellIdentityWcdma;
+    }
+    /** @hide */
+    public void setCellIdentity(CellIdentityWcdma cid) {
+        mCellIdentityWcdma = cid;
+    }
+
+    public CellSignalStrengthWcdma getCellSignalStrength() {
+        return mCellSignalStrengthWcdma;
+    }
+    /** @hide */
+    public void setCellSignalStrength(CellSignalStrengthWcdma css) {
+        mCellSignalStrengthWcdma = css;
+    }
+
+    /**
+     * @return hash code
+     */
+    @Override
+    public int hashCode() {
+        return super.hashCode() + mCellIdentityWcdma.hashCode() + mCellSignalStrengthWcdma.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (!super.equals(other)) {
+            return false;
+        }
+        try {
+            CellInfoWcdma o = (CellInfoWcdma) other;
+            return mCellIdentityWcdma.equals(o.mCellIdentityWcdma)
+                    && mCellSignalStrengthWcdma.equals(o.mCellSignalStrengthWcdma);
+        } catch (ClassCastException e) {
+            return false;
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append("CellInfoWcdma:{");
+        sb.append(super.toString());
+        sb.append(" ").append(mCellIdentityWcdma);
+        sb.append(" ").append(mCellSignalStrengthWcdma);
+        sb.append("}");
+
+        return sb.toString();
+    }
+
+    /** Implement the Parcelable interface */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags, TYPE_WCDMA);
+        mCellIdentityWcdma.writeToParcel(dest, flags);
+        mCellSignalStrengthWcdma.writeToParcel(dest, flags);
+    }
+
+    /**
+     * Construct a CellInfoWcdma object from the given parcel
+     * where the token is already been processed.
+     */
+    private CellInfoWcdma(Parcel in) {
+        super(in);
+        mCellIdentityWcdma = CellIdentityWcdma.CREATOR.createFromParcel(in);
+        mCellSignalStrengthWcdma = CellSignalStrengthWcdma.CREATOR.createFromParcel(in);
+    }
+
+    /** Implement the Parcelable interface */
+    public static final Creator<CellInfoWcdma> CREATOR = new Creator<CellInfoWcdma>() {
+        @Override
+        public CellInfoWcdma createFromParcel(Parcel in) {
+            in.readInt(); // Skip past token, we know what it is
+            return createFromParcelBody(in);
+        }
+
+        @Override
+        public CellInfoWcdma[] newArray(int size) {
+            return new CellInfoWcdma[size];
+        }
+    };
+
+    /** @hide */
+    protected static CellInfoWcdma createFromParcelBody(Parcel in) {
+        return new CellInfoWcdma(in);
+    }
+
+    /**
+     * log
+     */
+    private static void log(String s) {
+        Rlog.w(LOG_TAG, s);
+    }
+}
diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java
index 2c36344..d27fcec 100644
--- a/telephony/java/android/telephony/CellSignalStrengthGsm.java
+++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java
@@ -21,7 +21,7 @@
 import android.telephony.Rlog;
 
 /**
- * LTE signal strength related information.
+ * GSM signal strength related information.
  */
 public final class CellSignalStrengthGsm extends CellSignalStrength implements Parcelable {
 
@@ -30,7 +30,7 @@
 
     private static final int GSM_SIGNAL_STRENGTH_GREAT = 12;
     private static final int GSM_SIGNAL_STRENGTH_GOOD = 8;
-    private static final int GSM_SIGNAL_STRENGTH_MODERATE = 8;
+    private static final int GSM_SIGNAL_STRENGTH_MODERATE = 5;
 
     private int mSignalStrength; // Valid values are (0-31, 99) as defined in TS 27.007 8.5
     private int mBitErrorRate;   // bit error rate (0-7, 99) as defined in TS 27.007 8.5
@@ -67,7 +67,8 @@
     /**
      * Initialize all the values
      *
-     * @param SignalStrength
+     * @param ss SignalStrength as ASU value
+     * @param ber is Bit Error Rate
      *
      * @hide
      */
@@ -139,7 +140,7 @@
     }
 
     /**
-     * Get the LTE signal level as an asu value between 0..97, 99 is unknown
+     * Get the signal level as an asu value between 0..31, 99 is unknown
      * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
      */
     @Override
diff --git a/telephony/java/android/telephony/CellSignalStrengthWcdma.java b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
new file mode 100644
index 0000000..b94b01d
--- /dev/null
+++ b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.Rlog;
+
+/**
+ * Wcdma signal strength related information.
+ */
+public final class CellSignalStrengthWcdma extends CellSignalStrength implements Parcelable {
+
+    private static final String LOG_TAG = "CellSignalStrengthWcdma";
+    private static final boolean DBG = false;
+
+    private static final int WCDMA_SIGNAL_STRENGTH_GREAT = 12;
+    private static final int WCDMA_SIGNAL_STRENGTH_GOOD = 8;
+    private static final int WCDMA_SIGNAL_STRENGTH_MODERATE = 5;
+
+    private int mSignalStrength; // Valid values are (0-31, 99) as defined in TS 27.007 8.5
+    private int mBitErrorRate;   // bit error rate (0-7, 99) as defined in TS 27.007 8.5
+
+    /**
+     * Empty constructor
+     *
+     * @hide
+     */
+    public CellSignalStrengthWcdma() {
+        setDefaultValues();
+    }
+
+    /**
+     * Constructor
+     *
+     * @hide
+     */
+    public CellSignalStrengthWcdma(int ss, int ber) {
+        initialize(ss, ber);
+    }
+
+    /**
+     * Copy constructors
+     *
+     * @param s Source SignalStrength
+     *
+     * @hide
+     */
+    public CellSignalStrengthWcdma(CellSignalStrengthWcdma s) {
+        copyFrom(s);
+    }
+
+    /**
+     * Initialize all the values
+     *
+     * @param ss SignalStrength as ASU value
+     * @param ber is Bit Error Rate
+     *
+     * @hide
+     */
+    public void initialize(int ss, int ber) {
+        mSignalStrength = ss;
+        mBitErrorRate = ber;
+    }
+
+    /**
+     * @hide
+     */
+    protected void copyFrom(CellSignalStrengthWcdma s) {
+        mSignalStrength = s.mSignalStrength;
+        mBitErrorRate = s.mBitErrorRate;
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public CellSignalStrengthWcdma copy() {
+        return new CellSignalStrengthWcdma(this);
+    }
+
+    /** @hide */
+    @Override
+    public void setDefaultValues() {
+        mSignalStrength = Integer.MAX_VALUE;
+        mBitErrorRate = Integer.MAX_VALUE;
+    }
+
+    /**
+     * Get signal level as an int from 0..4
+     */
+    @Override
+    public int getLevel() {
+        int level;
+
+        // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
+        // asu = 0 (-113dB or less) is very weak
+        // signal, its better to show 0 bars to the user in such cases.
+        // asu = 99 is a special case, where the signal strength is unknown.
+        int asu = mSignalStrength;
+        if (asu <= 2 || asu == 99) level = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+        else if (asu >= WCDMA_SIGNAL_STRENGTH_GREAT) level = SIGNAL_STRENGTH_GREAT;
+        else if (asu >= WCDMA_SIGNAL_STRENGTH_GOOD)  level = SIGNAL_STRENGTH_GOOD;
+        else if (asu >= WCDMA_SIGNAL_STRENGTH_MODERATE)  level = SIGNAL_STRENGTH_MODERATE;
+        else level = SIGNAL_STRENGTH_POOR;
+        if (DBG) log("getLevel=" + level);
+        return level;
+    }
+
+    /**
+     * Get the signal strength as dBm
+     */
+    @Override
+    public int getDbm() {
+        int dBm;
+
+        int level = mSignalStrength;
+        int asu = (level == 99 ? Integer.MAX_VALUE : level);
+        if (asu != Integer.MAX_VALUE) {
+            dBm = -113 + (2 * asu);
+        } else {
+            dBm = Integer.MAX_VALUE;
+        }
+        if (DBG) log("getDbm=" + dBm);
+        return dBm;
+    }
+
+    /**
+     * Get the signal level as an asu value between 0..31, 99 is unknown
+     * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
+     */
+    @Override
+    public int getAsuLevel() {
+        // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
+        // asu = 0 (-113dB or less) is very weak
+        // signal, its better to show 0 bars to the user in such cases.
+        // asu = 99 is a special case, where the signal strength is unknown.
+        int level = mSignalStrength;
+        if (DBG) log("getAsuLevel=" + level);
+        return level;
+    }
+
+    @Override
+    public int hashCode() {
+        int primeNum = 31;
+        return (mSignalStrength * primeNum) + (mBitErrorRate * primeNum);
+    }
+
+    @Override
+    public boolean equals (Object o) {
+        CellSignalStrengthWcdma s;
+
+        try {
+            s = (CellSignalStrengthWcdma) o;
+        } catch (ClassCastException ex) {
+            return false;
+        }
+
+        if (o == null) {
+            return false;
+        }
+
+        return mSignalStrength == s.mSignalStrength && mBitErrorRate == s.mBitErrorRate;
+    }
+
+    /**
+     * @return string representation.
+     */
+    @Override
+    public String toString() {
+        return "CellSignalStrengthWcdma:"
+                + " ss=" + mSignalStrength
+                + " ber=" + mBitErrorRate;
+    }
+
+    /** Implement the Parcelable interface */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        if (DBG) log("writeToParcel(Parcel, int): " + toString());
+        dest.writeInt(mSignalStrength);
+        dest.writeInt(mBitErrorRate);
+    }
+
+    /**
+     * Construct a SignalStrength object from the given parcel
+     * where the token is already been processed.
+     */
+    private CellSignalStrengthWcdma(Parcel in) {
+        mSignalStrength = in.readInt();
+        mBitErrorRate = in.readInt();
+        if (DBG) log("CellSignalStrengthWcdma(Parcel): " + toString());
+    }
+
+    /** Implement the Parcelable interface */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface */
+    @SuppressWarnings("hiding")
+    public static final Parcelable.Creator<CellSignalStrengthWcdma> CREATOR =
+            new Parcelable.Creator<CellSignalStrengthWcdma>() {
+        @Override
+        public CellSignalStrengthWcdma createFromParcel(Parcel in) {
+            return new CellSignalStrengthWcdma(in);
+        }
+
+        @Override
+        public CellSignalStrengthWcdma[] newArray(int size) {
+            return new CellSignalStrengthWcdma[size];
+        }
+    };
+
+    /**
+     * log
+     */
+    private static void log(String s) {
+        Rlog.w(LOG_TAG, s);
+    }
+}
diff --git a/tests/CanvasCompare/AndroidManifest.xml b/tests/CanvasCompare/AndroidManifest.xml
index 1cb8c37..b55e290 100644
--- a/tests/CanvasCompare/AndroidManifest.xml
+++ b/tests/CanvasCompare/AndroidManifest.xml
@@ -15,8 +15,9 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.test.hwuicompare" >
 
-    <!-- for perfhud -->
     <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 
     <application
         android:label="@string/app_name"
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/AutomaticActivity.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/AutomaticActivity.java
index e0ff1dc..1ed4723 100644
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/AutomaticActivity.java
+++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/AutomaticActivity.java
@@ -16,11 +16,20 @@
 
 package com.android.test.hwuicompare;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.TreeSet;
 
-import com.android.test.hwuicompare.R;
+import org.json.JSONException;
+import org.json.JSONObject;
 
 import android.os.Bundle;
+import android.os.Environment;
 import android.os.Trace;
 import android.util.Log;
 import android.widget.ImageView;
@@ -31,20 +40,31 @@
     private static final float ERROR_DISPLAY_THRESHOLD = 0.01f;
     protected static final boolean DRAW_BITMAPS = false;
 
+    /**
+     * Threshold of error change required to consider a test regressed/improved
+     */
+    private static final float ERROR_CHANGE_THRESHOLD = 0.001f;
+
+    private static final float[] ERROR_CUTOFFS = {
+            0, 0.005f, 0.01f, 0.02f, 0.05f, 0.1f, 0.25f, 0.5f, 1f, 2f
+    };
+
+    private final float[] mErrorRates = new float[ERROR_CUTOFFS.length];
+    private float mTotalTests = 0;
+    private float mTotalError = 0;
+    private int mTestsRegressed = 0;
+    private int mTestsImproved = 0;
+
     private ImageView mSoftwareImageView = null;
     private ImageView mHardwareImageView = null;
 
-    private static final float[] ERROR_CUTOFFS = {0, 0.005f, 0.01f, 0.02f, 0.05f, 0.1f, 0.25f, 0.5f, 1f, 2f};
-    private float[] mErrorRates = new float[ERROR_CUTOFFS.length];
-    private float mTotalTests = 0;
-    private float mTotalError = 0;
 
-    public abstract static class TestCallback {
+    public abstract static class FinalCallback {
         abstract void report(String name, float value);
-        void complete() {}
+        void complete() {};
     }
 
-    private ArrayList<TestCallback> mTestCallbacks = new ArrayList<TestCallback>();
+    private final ArrayList<FinalCallback> mFinalCallbacks = new ArrayList<FinalCallback>();
 
     Runnable mRunnable = new Runnable() {
         @Override
@@ -64,32 +84,11 @@
             float error = mErrorCalculator.calcErrorRS(mSoftwareBitmap, mHardwareBitmap);
             Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
 
-            if (error > ERROR_DISPLAY_THRESHOLD) {
-                String modname = "";
-                for (String s : DisplayModifier.getLastAppliedModifications()) {
-                    modname = modname.concat(s + ".");
-                }
-                Log.d(LOG_TAG, String.format("error for %s was %2.9f", modname, error));
-            }
-            for (int i = 0; i < ERROR_CUTOFFS.length; i++) {
-                if (error <= ERROR_CUTOFFS[i]) break;
-                mErrorRates[i]++;
-            }
-            mTotalError += error;
-            mTotalTests++;
+            final String[] modifierNames = DisplayModifier.getLastAppliedModifications();
+            handleError(modifierNames, error);
 
             if (DisplayModifier.step()) {
-                for (TestCallback c : mTestCallbacks) {
-                    c.report("averageError", (mTotalError / mTotalTests));
-                    for (int i = 1; i < ERROR_CUTOFFS.length; i++) {
-                        c.report(String.format("error over %1.3f", ERROR_CUTOFFS[i]),
-                                mErrorRates[i]/mTotalTests);
-                    }
-                    c.complete();
-                }
-
-                Toast.makeText(getApplicationContext(), "done!", Toast.LENGTH_SHORT).show();
-                finish();
+                finishTest();
             } else {
                 mHardwareView.invalidate();
                 if (DRAW_BITMAPS) {
@@ -116,11 +115,186 @@
         mHardwareImageView = (ImageView) findViewById(R.id.hardware_image_view);
 
         onCreateCommon(mRunnable);
-        mTestCallbacks.add(new TestCallback() {
+        beginTest();
+    }
+
+    private static class TestResult {
+        TestResult(String label, float error) {
+            mLabel = label;
+            mTotalError = error;
+            mCount = 1;
+        }
+        public void addInto(float error) {
+            mTotalError += error;
+            mCount++;
+        }
+        public float getAverage() {
+            return mTotalError / mCount;
+        }
+        final String mLabel;
+        float mTotalError;
+        int mCount;
+    }
+
+    JSONObject mOutputJson = null;
+    JSONObject mInputJson = null;
+    final HashMap<String, TestResult> mModifierResults = new HashMap<String, TestResult>();
+    final HashMap<String, TestResult> mIndividualResults = new HashMap<String, TestResult>();
+    final HashMap<String, TestResult> mModifierDiffResults = new HashMap<String, TestResult>();
+    final HashMap<String, TestResult> mIndividualDiffResults = new HashMap<String, TestResult>();
+    private void beginTest() {
+        mFinalCallbacks.add(new FinalCallback() {
+            @Override
             void report(String name, float value) {
                 Log.d(LOG_TAG, name + " " + value);
             };
         });
+
+        File inputFile = new File(Environment.getExternalStorageDirectory(),
+                "CanvasCompareInput.json");
+        if (inputFile.exists() && inputFile.canRead() && inputFile.length() > 0) {
+            try {
+                FileInputStream inputStream = new FileInputStream(inputFile);
+                Log.d(LOG_TAG, "Parsing input file...");
+                StringBuffer content = new StringBuffer((int)inputFile.length());
+                byte[] buffer = new byte[1024];
+                while (inputStream.read(buffer) != -1) {
+                    content.append(new String(buffer));
+                }
+                mInputJson = new JSONObject(content.toString());
+                inputStream.close();
+                Log.d(LOG_TAG, "Parsed input file with " + mInputJson.length() + " entries");
+            } catch (JSONException e) {
+                Log.e(LOG_TAG, "error parsing input json", e);
+            } catch (IOException e) {
+                Log.e(LOG_TAG, "error reading input json from sd", e);
+            }
+        }
+
+        mOutputJson = new JSONObject();
+    }
+
+    private static void logTestResultHash(String label, HashMap<String, TestResult> map) {
+        Log.d(LOG_TAG, "---------------");
+        Log.d(LOG_TAG, label + ":");
+        Log.d(LOG_TAG, "---------------");
+        TreeSet<TestResult> set = new TreeSet<TestResult>(new Comparator<TestResult>() {
+            @Override
+            public int compare(TestResult lhs, TestResult rhs) {
+                if (lhs == rhs) return 0; // don't need to worry about complex equality
+
+                int cmp = Float.compare(lhs.getAverage(), rhs.getAverage());
+                if (cmp != 0) {
+                    return cmp;
+                }
+                return lhs.mLabel.compareTo(rhs.mLabel);
+            }
+        });
+
+        for (TestResult t : map.values()) {
+            set.add(t);
+        }
+
+        for (TestResult t : set.descendingSet()) {
+            if (Math.abs(t.getAverage()) > ERROR_DISPLAY_THRESHOLD) {
+                Log.d(LOG_TAG, String.format("%2.4f : %s", t.getAverage(), t.mLabel));
+            }
+        }
+        Log.d(LOG_TAG, "");
+    }
+
+    private void finishTest() {
+        for (FinalCallback c : mFinalCallbacks) {
+            c.report("averageError", (mTotalError / mTotalTests));
+            for (int i = 1; i < ERROR_CUTOFFS.length; i++) {
+                c.report(String.format("tests with error over %1.3f", ERROR_CUTOFFS[i]),
+                        mErrorRates[i]);
+            }
+            if (mInputJson != null) {
+                c.report("tests regressed", mTestsRegressed);
+                c.report("tests improved", mTestsImproved);
+            }
+            c.complete();
+        }
+
+        try {
+            if (mOutputJson != null) {
+                String outputString = mOutputJson.toString(4);
+                File outputFile = new File(Environment.getExternalStorageDirectory(),
+                        "CanvasCompareOutput.json");
+                FileOutputStream outputStream = new FileOutputStream(outputFile);
+                outputStream.write(outputString.getBytes());
+                outputStream.close();
+                Log.d(LOG_TAG, "Saved output file with " + mOutputJson.length() + " entries");
+            }
+        } catch (JSONException e) {
+            Log.e(LOG_TAG, "error during JSON stringify", e);
+        } catch (IOException e) {
+            Log.e(LOG_TAG, "error storing JSON output on sd", e);
+        }
+
+        logTestResultHash("Modifier change vs previous", mModifierDiffResults);
+        logTestResultHash("Invidual test change vs previous", mIndividualDiffResults);
+        logTestResultHash("Modifier average test results", mModifierResults);
+        logTestResultHash("Individual test results", mIndividualResults);
+
+        Toast.makeText(getApplicationContext(), "done!", Toast.LENGTH_SHORT).show();
+        finish();
+    }
+
+    /**
+     * Inserts the error value into all TestResult objects, associated with each of its modifiers
+     */
+    private static void addForAllModifiers(String fullName, float error, String[] modifierNames,
+            HashMap<String, TestResult> modifierResults) {
+        for (String modifierName : modifierNames) {
+            TestResult r = modifierResults.get(fullName);
+            if (r == null) {
+                modifierResults.put(modifierName, new TestResult(modifierName, error));
+            } else {
+                r.addInto(error);
+            }
+        }
+    }
+
+    private void handleError(final String[] modifierNames, final float error) {
+        String fullName = "";
+        for (String s : modifierNames) {
+            fullName = fullName.concat("." + s);
+        }
+        fullName = fullName.substring(1);
+
+        float deltaError = 0;
+        if (mInputJson != null) {
+            try {
+                deltaError = error - (float)mInputJson.getDouble(fullName);
+            } catch (JSONException e) {
+                Log.w(LOG_TAG, "Warning: unable to read from input json", e);
+            }
+            if (deltaError > ERROR_CHANGE_THRESHOLD) mTestsRegressed++;
+            if (deltaError < -ERROR_CHANGE_THRESHOLD) mTestsImproved++;
+            mIndividualDiffResults.put(fullName, new TestResult(fullName, deltaError));
+            addForAllModifiers(fullName, deltaError, modifierNames, mModifierDiffResults);
+        }
+
+        mIndividualResults.put(fullName, new TestResult(fullName, error));
+        addForAllModifiers(fullName, error, modifierNames, mModifierResults);
+
+        try {
+            if (mOutputJson != null) {
+                mOutputJson.put(fullName, error);
+            }
+        } catch (JSONException e) {
+            Log.e(LOG_TAG, "exception during JSON recording", e);
+            mOutputJson = null;
+        }
+
+        for (int i = 0; i < ERROR_CUTOFFS.length; i++) {
+            if (error <= ERROR_CUTOFFS[i]) break;
+            mErrorRates[i]++;
+        }
+        mTotalError += error;
+        mTotalTests++;
     }
 
     @Override
@@ -130,7 +304,7 @@
     }
 
     // FOR TESTING
-    public void setCallback(TestCallback c) {
-        mTestCallbacks.add(c);
+    public void setFinalCallback(FinalCallback c) {
+        mFinalCallbacks.add(c);
     }
 }
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/Test.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/Test.java
index 6ea8237..1ff153c 100644
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/Test.java
+++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/Test.java
@@ -1,6 +1,6 @@
 package com.android.test.hwuicompare;
 
-import com.android.test.hwuicompare.AutomaticActivity.TestCallback;
+import com.android.test.hwuicompare.AutomaticActivity.FinalCallback;
 
 import android.os.Bundle;
 import android.test.ActivityInstrumentationTestCase2;
@@ -18,7 +18,7 @@
         super.setUp();
         mBundle = new Bundle();
         mActivity = getActivity();
-        mActivity.setCallback(new TestCallback() {
+        mActivity.setFinalCallback(new FinalCallback() {
 
             @Override
             void report(String key, float value) {
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/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index f73a13c..4e7497c 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -19,17 +19,12 @@
 import android.os.Parcelable;
 import android.os.Process;
 import android.security.Credentials;
+import android.security.KeyStore;
 import android.text.TextUtils;
 
-import com.android.org.bouncycastle.asn1.ASN1InputStream;
-import com.android.org.bouncycastle.asn1.ASN1Sequence;
-import com.android.org.bouncycastle.asn1.DEROctetString;
-import com.android.org.bouncycastle.asn1.x509.BasicConstraints;
-
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.security.KeyFactory;
-import java.security.KeyStore;
 import java.security.NoSuchAlgorithmException;
 import java.security.PrivateKey;
 import java.security.cert.Certificate;
@@ -481,7 +476,8 @@
         String caCertName = Credentials.CA_CERTIFICATE + name;
         if (mClientCertificate != null) {
             byte[] privKeyData = mClientPrivateKey.getEncoded();
-            ret = keyStore.importKey(privKeyName, privKeyData, Process.WIFI_UID);
+            ret = keyStore.importKey(privKeyName, privKeyData, Process.WIFI_UID,
+                            KeyStore.FLAG_ENCRYPTED);
             if (ret == false) {
                 return ret;
             }
@@ -525,7 +521,7 @@
             Certificate cert) {
         try {
             byte[] certData = Credentials.convertToPem(cert);
-            return keyStore.put(name, certData, Process.WIFI_UID);
+            return keyStore.put(name, certData, Process.WIFI_UID, KeyStore.FLAG_ENCRYPTED);
         } catch (IOException e1) {
             return false;
         } catch (CertificateException e2) {
@@ -533,7 +529,7 @@
         }
     }
 
-    void removeKeys(android.security.KeyStore keyStore) {
+    void removeKeys(KeyStore keyStore) {
         String client = getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX);
         // a valid client certificate is configured
         if (!TextUtils.isEmpty(client)) {